Android Room数据库事务

时间:2017-06-23 02:01:00

标签: android transactions android-database android-room

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

removeRows(ids);
insertRows(ids);

如果我运行它,我会看到(在检查数据库时)缺少某些行 - 我认为它们在插入后会被删除。即第一个操作与第二个操作并行运行。

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

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

insertRows(ids);

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

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

insertRows(ids);

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

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

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

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

5 个答案:

答案 0 :(得分:22)

Transaction的文档所指出,您可以执行以下操作:

DECLARE @PeriodStamp VARCHAR(8000) = REPLACE(CAST(GETDATE() - 2 AS DATE), '-', '')

DECLARE @marketingoptinp1 VARCHAR(8000) = '''bcp "select ''''Created_DateTime'''', ''''Application_Date'''', ''''Application_ID'''', ''''Customer_ID'''', ''''First_Name'''', ''''Last_Name'''', ''''Email'''', ''''Mobile_Phone'''', ''''Home_Phone'''', ''''Gender'''', ''''DOB'''', ''''AGE'''',  ''''Marital_Status_ID'''', ''''Marital_Status_Desc'''', ''''Dependent_Number'''', ''''Dependent_Number_Desc'''', ''''Employment_Industry_ID'''', ''''Employment_Industry_Desc'''', ''''Income_Source_ID'''', ''''Income_Source_Desc'''', ''''Loan_Amount'''', ''''Loan_Purpose_ID'''', ''''Loan_Purpose_Desc'''', ''''Residence_Type_ID'''', ''''Residence_Type_Desc'''', ''''Postcode'''', ''''Address1'''', ''''Address2'''', ''''City'''', ''''County'''', ''''Marketing_Opt_In'''', ''''IP_Address'''', ''''Bank_Sort_Code'''', ''''Device'''', ''''Lender_Result'''', ''''Rental_Mortgage_Payments'''', ''''Has_Pension'''', ''''PeriodStamp'''' union all SELECT Created_DateTime, cast(Application_Date as nvarchar(10)) as Application_Date, cast(Application_ID as nvarchar(15)) as Application_ID, cast(Customer_ID as nvarchar(15)) as Customer_ID , cast(First_Name as varchar(150)) as First_Name , cast(Last_Name as varchar(150)) as Last_Name , cast(Email as varchar(250)) as Email , quintegrity.[dbo].[udf_AlphaNumericElement](Mobile_Phone,4) as Mobile_Phone , quintegrity.[dbo].[udf_AlphaNumericElement](Home_Phone,4) as Home_Phone , Gender, cast(DOB as nvarchar(15)) as DOB, cast(AGE as nvarchar(3)) as AGE, cast(Marital_Status_ID as nvarchar(2)) as Marital_Status_ID, Marital_Status_Desc,  cast(Dependent_Number as nvarchar(20)) as Dependent_Number, Dependent_Number_Desc, cast(Employment_Industry_ID as nvarchar(10)) as Employment_Industry_ID, Employment_Industry_Desc, cast(Income_Source_ID as nvarchar(10)), Income_Source_Desc, cast(Loan_Amount as nvarchar(20)) as Loan_Amount, cast(Loan_Purpose_ID as nvarchar(6)) as Loan_Purpose_ID, Loan_Purpose_Desc,  cast(Residence_Type_ID as nvarchar(6)) as Residence_Type_ID, Residence_Type_Desc , cast(Postcode as varchar(150)) Postcode  , cast(Address1 as varchar(150)) Address1 , cast(Address2 as varchar(150)) Address2 , cast(City as varchar(150)) City , cast(County as varchar(150)) County , cast(Marketing_Opt_In as nvarchar(2)) as Marketing_Opt_In,  cast(IP_Address as nvarchar(20)) as IP_Address, cast(Bank_Sort_Code as nvarchar(10)) as Bank_Sort_Code, Device, Lender_Result, cast(Rental_Mortgage_Payments as nvarchar(15)) as Rental_Mortgage_Payments, Has_Pension, PeriodStamp FROM scratch.dbo.data_extract where Marketing_Opt_In = 1 and PeriodStamp = ' + @PeriodStamp 

DECLARE @marketingoptinp2 VARCHAR(8000) 
SET @marketingoptinp2 = ' " queryout "C:\test\data' + @PeriodStamp+'.txt" -T -c'''

DECLARE @cmd VARCHAR(8000)
SET @cmd = @marketingoptinp1 + @marketingoptinp2

EXEC xp_cmdshell @cmd

答案 1 :(得分:14)

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

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

roomDB.runInTransaction(new Runnable() {
        @Override
        public void run() {
            removeRows(ids);
            insertRows(ids);
        }
    });

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

答案 2 :(得分:1)

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

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

    @Insert 
    fun insert(item: Item)

    @Delete 
    fun delete(item: Item)

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

}
  • 或使用打开功能,例如:
@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)
    }

}

如果没有打开修饰符,您将获得error: Method annotated with @Transaction must not be private, final, or abstract.

答案 3 :(得分:0)

这是解决此问题的方法:

@Query("SELECT * FROM friend WHERE id = :id")
Friend getFriendByID(int id);
@Delete
void delete(Friend friend);

Friend friendToBeDeleted = friendDAO.getFriendByID(id);
friendDAO.delete(friendToBeDeleted);

您必须经历两个步骤!

答案 4 :(得分:0)

我相信当我们使用DAO接口时,仍然可以使用默认接口方法执行事务。我们需要添加注释@JvmDefault和@Transaction,我们可以在其中执行任何操作,这些操作属于单个事务。

@Dao
interface TestDao {
    @Insert
    fun insert(dataObj: DataType)

    @Update
    fun update(dataObj: DataType): Completable

    @Delete
    fun delete(dataObj: DataType): Completable

    @Query("DELETE FROM $TABLE_NAME")
    fun deleteAllData()

    @Query("SELECT * FROM $TABLE_NAME ORDER BY id DESC")
    fun getAllData(): Single<List<DataType>>

    @JvmDefault
    @Transaction
    fun singleTransaction(dataList: List<DataType>) {
        deleteAllData()
        dataList.forEach {
            insert(it)
        }
    }
}