已编辑:
是,SQLite doesn't support嵌套事务,但docs声明SQLiteDatabase确实存在。
情境
我有一个包含事务的方法,我需要从另一个事务中调用此方法。
另外 - 两个事务都在同一组记录上工作,但更新不同的列。
的问题
看起来我的外部交易的结果被内部交易取消,仍然都被setTransactionSuccessful()标记为清理并且由endTransaction()完成 - 我已经检查了这一点。
的问题
- 知道为什么会这样吗?
- 是否有推荐的方式进行此类交易?
答案 0 :(得分:5)
您可以使用caveats:
与Android sqlite API嵌套交易交易可以嵌套。当外部事务结束时,该事务中完成的所有工作以及所有嵌套事务都将被提交或回滚。如果任何事务结束而没有标记为干净(通过调用setTransactionSuccessful),则将回滚更改。否则他们将被承诺。
我见过的另一种与sqlite一起使用的方法是传入一个布尔参数isInTransaction
,它告诉被调用的方法它是应该自己处理事务,还是让调用者处理事务。
答案 1 :(得分:5)
"嵌套Android交易" not 使用SQLites嵌套事务/保存点支持。
而是嵌套的Android事务禁止显示SQLite事务。嵌套事务不能自行回滚,因为除了外部事务之外它不存在。这可以be seen here与mTransactionStack == null
后卫。
实际支持嵌套事务的唯一方法 - SQLite 支持支持,而不是BEGIN / COMMIT - 是手动使用SAVEPOINT / RELEASE命令。当然,设计不依赖于此的代码将消除这需要的额外手动管理。
(我可能会将所有交易工作从实际的单个操作中移出,将管理层留给高级调用者;这对于UoW模式非常有效,但可能并不总是适用。)
答案 2 :(得分: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();
}
}
答案 3 :(得分:1)
您可以通过这种方式在execSQL()
中使用savepoints的原始SQL来执行嵌套事务:
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#executeSpecial
和android.database.sqlite.SQLiteSession#execute
的代码。