使用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
中。
答案 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)
}
}
}