Android Room DAO 如何在一个事务中运行 多个 DAO 方法?
Android Room DAO how to run several DAO methods in a single transaction?
考虑以下 Room DAO
@Dao
public abstract class JobDao {
@Insert
public abstract long insert( Job v );
@Update
public abstract int update( Job v );
@Insert
public abstract long insertPerson( Person p );
@Update
public abstract int updatePerson( Person p );
@Transaction
public void insertNetJobs( List<NetJob> list ) {
Timber.d("--- insert page start");
for( NetJob j : list ) {
if ( updatePerson( j.getPerson() ) == 0 ) {
insertPerson( j.getPerson() );
}
insert( j.getJob() );
}
Timber.d("--- insert page end");
}
}
根据文档,在单个事务中标有@Transaction 运行s 的方法内部的任何内容。但实际上它 运行 是整个方法 insertNetJobs 的一个事务和每个调用 updatePerson、insertPerson、insert 的内部事务。所以日志看起来像这样
D/JobDao: ---- insert page start
D/SQLiteDatabase: beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
........................
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
D/JobDao: ---- insert page end
因此,insertNetJobs 方法运行速度非常慢。有没有可能 运行 这种方法只使用一次交易?
试试这个
roomDB.runInTransaction(new Runnable() {
@Override
public void run() {
Timber.d("--- insert page start");
for( NetJob j : list ) {
if ( updatePerson( j.getPerson() ) == 0 ) {
insertPerson( j.getPerson() );
}
insert( j.getJob() );
}
Timber.d("--- insert page end");
}
});
好的,我知道问题出在哪里了。如果有人有类似的问题,这里有一个解释。实际问题出在更新查询上。执行它大约需要 20ms。
此代码:
@Update
public abstract int updatePerson( Person p );
生成以下查询:
UPDATE OR ABORT `sw_person` SET `id` = ?,`id_s` = ?,`id_lang` = ?,`name` = ? WHERE `id` = ?
此查询更新此人 table 的 pk,但在其他 table 中,此密钥用作 fk,导致在 table 中查找。遗憾的是"room"在update query中更新了pk,可能解决办法是手动写query。
考虑以下 Room DAO
@Dao
public abstract class JobDao {
@Insert
public abstract long insert( Job v );
@Update
public abstract int update( Job v );
@Insert
public abstract long insertPerson( Person p );
@Update
public abstract int updatePerson( Person p );
@Transaction
public void insertNetJobs( List<NetJob> list ) {
Timber.d("--- insert page start");
for( NetJob j : list ) {
if ( updatePerson( j.getPerson() ) == 0 ) {
insertPerson( j.getPerson() );
}
insert( j.getJob() );
}
Timber.d("--- insert page end");
}
}
根据文档,在单个事务中标有@Transaction 运行s 的方法内部的任何内容。但实际上它 运行 是整个方法 insertNetJobs 的一个事务和每个调用 updatePerson、insertPerson、insert 的内部事务。所以日志看起来像这样
D/JobDao: ---- insert page start
D/SQLiteDatabase: beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
........................
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
beginTransaction()
D/SQLiteDatabase: endTransaction()
D/JobDao: ---- insert page end
因此,insertNetJobs 方法运行速度非常慢。有没有可能 运行 这种方法只使用一次交易?
试试这个
roomDB.runInTransaction(new Runnable() {
@Override
public void run() {
Timber.d("--- insert page start");
for( NetJob j : list ) {
if ( updatePerson( j.getPerson() ) == 0 ) {
insertPerson( j.getPerson() );
}
insert( j.getJob() );
}
Timber.d("--- insert page end");
}
});
好的,我知道问题出在哪里了。如果有人有类似的问题,这里有一个解释。实际问题出在更新查询上。执行它大约需要 20ms。
此代码:
@Update
public abstract int updatePerson( Person p );
生成以下查询:
UPDATE OR ABORT `sw_person` SET `id` = ?,`id_s` = ?,`id_lang` = ?,`name` = ? WHERE `id` = ?
此查询更新此人 table 的 pk,但在其他 table 中,此密钥用作 fk,导致在 table 中查找。遗憾的是"room"在update query中更新了pk,可能解决办法是手动写query。