Android Room数据库事务

raj*_*ath 22 android transactions android-database android-room

使用Android中的新房间数据库,我需要有两个顺序操作需要进行:

removeRows(ids);
insertRows(ids);
Run Code Online (Sandbox Code Playgroud)

如果我运行它,我看到(在检查数据库时)有一些行丢失 - 我假设它们在插入后被删除.即 第一个操作与第二个操作并行运行.

如果我使用一个事务块,比如这个,那么一切都很好 - 第一个操作似乎在完成第二个之前完成:

roomDb.beginTransaction();
removeRows(ids);
roomDb.endTransaction();

insertRows(ids);
Run Code Online (Sandbox Code Playgroud)

如果我在中间睡觉,那也没关系:

removeRows(ids);
Thread.sleep(500);

insertRows(ids);
Run Code Online (Sandbox Code Playgroud)

Room似乎没有太多的文档,并且想知道我是否应该在完成顺序操作时使用上面的事务块,或者是否有更好的方法.

编辑:在@CommonsWare指出之后,@Query是异步的,@Insert而且@Delete是同步的.鉴于此,我如何获得删除行异步的查询:

@Query("DELETE from table WHERE id IN(:ids)")
int removeRows(List<Long> ids);
Run Code Online (Sandbox Code Playgroud)

根据我得到的构建输出Deletion methods must either return void or return int (the number of deleted rows),如果我尝试将返回类型包装在一个Flowable.

gun*_*ess 26

正如在Transaction的文档中指出的那样,您可以执行以下操作:

 @Dao
 public abstract class ProductDao {
    @Insert
    public abstract void insert(Product product);

    @Delete
    public abstract void delete(Product product);

    @Transaction
    public void insertAndDeleteInTransaction(Product newProduct, Product oldProduct) {
         // Anything inside this method runs in a single transaction.
         insert(newProduct);
         delete(oldProduct);
     }
 }
Run Code Online (Sandbox Code Playgroud)

  • @johnny_crq我使用的是接口,切换到抽象类并不困难.或者你可以在一个方法的接口`@Transaction @Query("DELETE FROM products; INSERT INTO products VALUES(x,y,z)")上尝试这个丑陋的技巧. (4认同)
  • 如果我使用接口怎么办? (3认同)
  • @LukaszTaraszka我认为对于这种情况,数据库本身有一个方法。它应该像``db.startTransaction(); aDao.do(); bDao.do(); db.endTransaction()``` 或一些 kotlin 风格的块。但你必须在 dao 之外进行。但你必须小心异步查询。 (2认同)

Pin*_*kin 18

正如@CommonsWare指出的那样,@ Query是异步的,而@ Insert,@ Delete,@ Update是同步的.

如果要在单个事务中执行多个查询,Room还提供了一种方法,如下所述.

roomDB.runInTransaction(new Runnable() {
        @Override
        public void run() {
            removeRows(ids);
            insertRows(ids);
        }
    });
Run Code Online (Sandbox Code Playgroud)

我希望这能解决你的问题.

  • PCMIIW:查询并不总是异步的.只有在返回可观察的例如Flowable或LiveData时,查询才是异步的.因为在Query中使用了删除元素的问题,返回值是int,因此它将同步运行. (5认同)
  • 对于任何想知道的人:[runInTransaction](https://developer.android.com/reference/android/arch/persistence/room/RoomDatabase#runInTransaction\(java.lang.Runnable\)): _"[...]The除非在 Runnable 中抛出异常,否则事务将被标记为成功。”_ (2认同)

Dan*_*iel 11

对于 Kotlin 中的 Room 交易,您可以使用:

  • 与已实现方法的接口,例如:
@Dao 
interface Dao {

    @Insert 
    fun insert(item: Item)

    @Delete 
    fun delete(item: Item)

    @Transaction
    fun replace(oldItem: Item, newItem: Item){
        delete(oldItem)
        insert(newItem)
    }

}
Run Code Online (Sandbox Code Playgroud)
  • 或者使用open函数,例如:
@Dao 
abstract class Dao {

    @Insert 
    abstract fun insert(item: Item)

    @Delete 
    abstract fun delete(item: Item)

    @Transaction
    open fun replace(oldItem: Item, newItem: Item){
        delete(oldItem)
        insert(newItem)
    }

}
Run Code Online (Sandbox Code Playgroud)

您将error: Method annotated with @Transaction must not be private, final, or abstract.无需打开修改器即可获得。