Android 跨 DAO 的房间交易

Android Room transactions across DAOs

官方文档指出:

It is recommended to have multiple Dao classes in your codebase depending on the tables they touch.

并且可以用这样的 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);
     }
 }

但是如果一个事务跨越多个 DAO 怎么办?我应该将所有 DAO 合并为一个以支持交易,还是有更好的方法来做到这一点?

您可以使用RoomDatabase.runInTransaction(...)

类似于:

database.runInTransaction(new Runnable(){
  @Override
  public void run(){
    Access all your daos here
  }
});

事实 1: 在方法上使用@Transaction 会导致在Dao_Impl 生成的class 中覆盖该方法。此方法如下所示:

  @Override
  public void makeFieldInactive(final long fieldId) {
      __db.beginTransaction();
      try {
          MyDao_Impl.super.makeFieldInactive(fieldId);
          __db.setTransactionSuccessful();
      } finally {
          __db.endTransaction();
      }
  }

事实 2: 运行InTransaction() 方法如下所示:

/**
 * Executes the specified {@link Runnable} in a database transaction. The transaction will be
 * marked as successful unless an exception is thrown in the {@link Runnable}.
 * <p>
 * Room will only perform at most one transaction at a time.
 *
 * @param body The piece of code to execute.
 */
@SuppressWarnings("deprecation")
public void runInTransaction(@NonNull Runnable body) {
    beginTransaction();
    try {
        body.run();
        setTransactionSuccessful();
    } finally {
        endTransaction();
    }
}

结论: 他们都做同样的事情。

更多信息: 我已经做了一些测试,看起来使用其中一个(或两个,冗余)将成功地导致你的道方法在一次交易中 运行。

答案: 在访问同一个数据库的多个 Daos 中进行更改的方法上使用 @Transaction 是确保方法中发生的所有数据库操作发生在一个事务中的安全方法。

编辑: 在标记为 @Transactoin:

的一种方法中访问多个 Dao 的示例
@Transaction
 public void addItem(ItemEntity item) {
        item.setId(insert(item));
        ItemReportDao itemReportDao = AppDatabase.getIntance().itemReportDao();
        itemReportDao.addItemReport(item.getId());
}