【问题标题】:Room Transaction rollback房间交易回滚
【发布时间】:2021-09-19 06:41:38
【问题描述】:

根据room documentation事务回滚事务中的每个查询以防出错。

所以我在这里测试了回滚:

@Transaction
public Completable updateTable1(Table table1) {
    return Completable.fromAction(
            () -> 
                table1.setNotice("why am i updateed????");
                synchronousUpdate(table1);
                table1.setForeignKeyId(90); //some random foreign key which does not exsist so it throws an exception
                synchronousUpdate(table1);
            }
    );
}

@Update
void synchronousUpdate(T obj);

即使第二次更新引发错误,我的 table1 仍然会更新。

原因可能是什么?我是因为我返回一个可完成的而不是像 void 这样的同步返回值?

【问题讨论】:

    标签: sql sqlite android-sqlite android-room


    【解决方案1】:

    文件说

    除非在方法体中抛出异常,否则事务将被标记为成功。

    实际上并没有说异常将被管理,尽管 ROLLBACK 将跳过,即 setTransactionSuccessful 被跳过并执行 endTransaction。如果您查看生成的代码,例如编码方法是:-

    @Transaction
    public boolean update4(Bookmark b1, Bookmark b2) {
        if (update(b1) > 0) {
            if (update(b2) < 1) {
                abort(b1);
                return false;
            }
        } else {
                abort(b1);
            return false;
        }
        return true;
    }
    

    Room生成的代码是:-

      @Override
      public boolean update4(final Bookmark b1, final Bookmark b2) {
        __db.beginTransaction();
        try {
          boolean _result = AllDao_Impl.super.update4(b1, b2);
          __db.setTransactionSuccessful();
          return _result;
        } finally {
          __db.endTransaction();
        }
      }
    

    没有catch,所以你需要相应地处理异常。

    考虑以下(给出的先前答案的修改版本):-

        b1.setPostUrl("YetAnotherURL");
        b5.setPostTitle("P5");
        b5.setPostUrl("U5");
        try {
            dao.update4(b1, b5);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        logInfo("-D1");
        dao.update4(b1,b5);
        logInfo("-D2");
    

    基本上相同的更新,由于 id 不存在而不会更新(返回 0),运行两次。不同之处在于第一个是在 try/catch 块中。

    日志结果:-

    2021-07-09 12:04:38.344 W/System.err: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: mylist_data.ID (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
    2021-07-09 12:04:38.348 W/System.err:     at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
    2021-07-09 12:04:38.349 W/System.err:     at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
    2021-07-09 12:04:38.349 W/System.err:     at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
    2021-07-09 12:04:38.349 W/System.err:     at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
    2021-07-09 12:04:38.349 W/System.err:     at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
    2021-07-09 12:04:38.349 W/System.err:     at androidx.room.EntityInsertionAdapter.insertAndReturnId(EntityInsertionAdapter.java:114)
    2021-07-09 12:04:38.349 W/System.err:     at a.a.so67958704javaroomconvertexistingdb.AllDao_Impl.abort(AllDao_Impl.java:133)
    2021-07-09 12:04:38.349 W/System.err:     at a.a.so67958704javaroomconvertexistingdb.AllDao.update4(AllDao.java:40)
    2021-07-09 12:04:38.350 W/System.err:     at a.a.so67958704javaroomconvertexistingdb.AllDao_Impl.access$001(AllDao_Impl.java:22)
    2021-07-09 12:04:38.350 W/System.err:     at a.a.so67958704javaroomconvertexistingdb.AllDao_Impl.update4(AllDao_Impl.java:159)
    2021-07-09 12:04:38.350 W/System.err:     at a.a.so67958704javaroomconvertexistingdb.MainActivity.onCreate(MainActivity.java:78)
    ....
    2021-07-09 12:04:38.353 D/BMINFO-D1: ID = 1 PostTitle = P1 PostURL =AnotherURL
    2021-07-09 12:04:38.353 D/BMINFO-D1: ID = 2 PostTitle = P2 PostURL =U2
    2021-07-09 12:04:38.353 D/BMINFO-D1: ID = 3 PostTitle = P3 PostURL =U3
    2021-07-09 12:04:38.353 D/BMINFO-D1: ID = 4 PostTitle = P4 PostURL =U4
    2021-07-09 12:04:38.355 D/AndroidRuntime: Shutting down VM
    2021-07-09 12:04:38.358 E/AndroidRuntime: FATAL EXCEPTION: main
        Process: a.a.so67958704javaroomconvertexistingdb, PID: 14230
        java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so67958704javaroomconvertexistingdb/a.a.so67958704javaroomconvertexistingdb.MainActivity}: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: mylist_data.ID (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
    

    注意第一个异常被捕获并打印出来,不是致命异常,第二个是。

    【讨论】:

    • 我明白了,既然房间确实管理了一个发生的异常,它“假设”交易是有效的?
    • @FunnyMoments 我想说的更多是因为它正确地管理事务,即无论如何都不会留下不完整的事务。
    • 在您的示例中考虑中止功能。在这种情况下,中止究竟是如何工作的?像房间的预定义功能吗?
    • @FunnyMoments 只是尝试使用 ABORT 的 onConflict 策略插入副本(根据我之前的回答),即@Insert(onConflict = OnConflictStrategy.ABORT) abstract long abort(Bookmark bookmark);。这不是 Room 功能。
    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 2014-10-29
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    相关资源
    最近更新 更多