SQLiteDatabase嵌套事务和变通方法

时间:2014-09-29 18:15:50

标签: java android sqlite transactions

已编辑:
是,SQLite doesn't support嵌套事务,但docs声明SQLiteDatabase确实存在。
情境
我有一个包含事务的方法,我需要从另一个事务中调用此方法。
另外 - 两个事务都在同一组记录上工作,但更新不同的列。
问题
看起来我的外部交易的结果被内部交易取消,仍然都被setTransactionSuccessful()标记为清理并且由endTransaction()完​​成 - 我已经检查了这一点。
问题
- 知道为什么会这样吗?
- 是否有推荐的方式进行此类交易?

4 个答案:

答案 0 :(得分:5)

您可以使用caveats

与Android sqlite API嵌套交易
  

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

我见过的另一种与sqlite一起使用的方法是传入一个布尔参数isInTransaction,它告诉被调用的方法它是应该自己处理事务,还是让调用者处理事务。

答案 1 :(得分:5)

"嵌套Android交易" not 使用SQLites嵌套事务/保存点支持。

而是嵌套的Android事务禁止显示SQLite事务。嵌套事务不能自行回滚,因为除了外部事务之外它不存在。这可以be seen heremTransactionStack == 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#executeSpecialandroid.database.sqlite.SQLiteSession#execute的代码。