2014-09-29 92 views
5

编辑:
是,SQLite的doesn't support嵌套事务,但docs声明SQLiteDatabase一样。
情况
我有一个包含事务的方法,我需要从另一个事务中调用这个方法。
此外 - 这两个事务处理同一组记录,但更新不同的列。
问题
看起来我的外部事务的结果被内部的一个取消,仍然都被setTransactionSuccessful()标记为clean并由endTransaction()完​​成 - 我已经检查过了。
问题
- 任何想法为什么会发生这种情况?
- 有没有推荐的方法来做这样的交易?SQLiteDatabase嵌套事务和解决方法

回答

5

您可以嵌套事务与Android的SQLite API,与caveats

交易可以被嵌套。当外部事务结束时,在该事务中完成的所有工作和所有嵌套事务将被提交或回滚。如果任何事务没有被标记为干净(通过调用setTransactionSuccessful),则更改将被回滚。否则他们会承诺。

我见过的一般使用SQLite的另一种方法是,告诉被调用的方法是否应该自行处理交易,或让来电处理事务的布尔参数isInTransaction通过。

+0

谢谢。 [文档](http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#beginTransaction())允许嵌套事务,但它看起来像我的外部事务结果在某种程度上被内部事务结果取消事务处理同一组记录,但更新不同的列)。 /顺便说一句,你有任何想法如何可能发生??/ 现在我使用有条件的交易(类似于你的建议),所以我会坚持下去 – sberezin 2014-09-29 19:38:54

5

“嵌套Android交易”做而不是使用SQLite嵌套事务/保存点支持。

相反,嵌套的Android事务会抑制显示SQLite事务。嵌套事务不能本身回滚,因为除了外部事务外它不存在。这可以be seen heremTransactionStack == null后卫。

只有这样,才能真正支持内嵌事务 - 这SQLite的确实支持,只是不能与开始/提交 - 是手动使用SAVEPOINT/RELEASE命令。当然,设计代码不依赖于此将消除这需要的额外手动管理。

(我可能把所有的事务工作中摆脱个人实际操作,使管理高层主叫方;这工作得相当好了UOW模式,但可能并不总是适用)

2

现在我结束了对称方法设计(类似于laalto建议),它提供了正确的工作。这是一个解决方法,明确地将嵌套事务“转换”为单一事务。
现在我可以分开或者从另一个地打电话给他们(没有我仍然不明白的副作用)。
这就是:

public void method1() { 
    SQLiteDatabase db = dbhelper.getWritableDatabase(); 

    boolean doAsTransaction = !db.inTransaction(); 

    if (doAsTransaction) 
     db.beginTransaction(); 

    try { 
     // ... 
     if (doAsTransaction) 
      db.setTransactionSuccessful(); 

    } catch (Exception e) { 
     // ... 

    } finally { 
     // ... 
     if (doAsTransaction) 
      db.endTransaction(); 
    } 
} 


public void method2() { 
    SQLiteDatabase db = dbhelper.getWritableDatabase(); 

    boolean doAsTransaction = !db.inTransaction(); 

    if (doAsTransaction) 
     db.beginTransaction(); 

    try { 
     // ... 
     method1(); 
     if (doAsTransaction) 
      db.setTransactionSuccessful(); 

    } catch (Exception e) { 
     // ... 

    } finally { 
     // ... 
     if (doAsTransaction) 
      db.endTransaction(); 
    } 
} 
0

您可以通过使用savepoints原始的SQL在execSQL()以这种方式进行嵌套事务:

db.execSql("SAVEPOINT test"); // declare savepoint 
// ... do some operations 
db.execSql(";ROLLBACK TO test"); // rollback 
db.execSql("RELEASE test"); // save changes 

分号ROLLBACK的前面是必需的,因为没有它的Android数据库框架将尝试呼叫endTransaction()。有关详细信息,请参阅方法android.database.sqlite.SQLiteSession#executeSpecialandroid.database.sqlite.SQLiteSession#execute的代码。