rawQuery 有时在数据库中找不到该项目(多线程问题)



我在rawQuery上遇到了问题。有时它不会通过其 ID 找到项目,而有时它会。

我的逻辑如下:我从网络服务中检索一些数据。我将其与本地数据库同步,然后从本地数据库(而不是从我从 Web 服务接收的内容(将响应返回给用户。

我的问题是,当我同步数据时,rawQuery从本地数据库中检索该项目以查看我是否已经拥有它。如果找不到,它会插入一个新行,如果找不到,则只会更新它。方法如下:

@Override
public ShopItem syncShop(ShopItem remoteShop) {
SQLiteDatabase db = DbManager.instance().openDatabase();
Cursor c = db.rawQuery(
DBContract.SHOPS.GET_SHOP_BY_REMOTE_ID,
new String[]{String.valueOf(remoteShop.remote_id)});
if (c.moveToFirst()) {//Item(s) exist
ShopItem localShop = new ShopItem(c);
if (localShop.updateDate == null || !localShop.updateDate.equals(remoteShop.updateDate)) {
localShop.sync(remoteShop);
db.update(DBContract.SHOPS.TABLE_NAME, localShop.getDbContentValues(),
DBContract.SHOPS.REMOTE_OBJ_ID + " = ?", new String[]{localShop.remote_id});
}
remoteShop = localShop;
} else {//No item(s) found
ContentValues values = remoteShop.getDbContentValues();
long rowId = db.insert(DBContract.SHOPS.TABLE_NAME, null, values);
if (rowId != -1) {
remoteShop.local_id = String.valueOf(rowId);
}
}
free(db, c);
return remoteShop;
}

我尝试连续调用此方法 20 次(仅用于调试目的(,并且其中一些c.moveToFirst()是错误的,因此它会插入一个新项目而不是更新它。

在 UI 线程上,20 个调用工作正常,它们不会创建新项目......但是我最近将对上述方法的调用转移到非 UI 线程,从那时起它就开始起作用。我 100% 肯定这是一个多线程问题,但我无法弄清楚问题出在哪里。

这是DbManager

/*package*/ class DbManager {
private int mOpenCounter;
private static DbManager mInstance;
private static DbHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;
public static synchronized void initializeInstance(DbHelper helper) {
if (mInstance == null) {
mInstance = new DbManager();
mDatabaseHelper = helper;
}
}
public static synchronized DbManager instance() {
if (mInstance == null) {
throw new IllegalStateException(DbManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return mInstance;
}
public synchronized SQLiteDatabase openDatabase() {
mOpenCounter++;
if (mOpenCounter == 1) {
// Opening new database
mDatabase = mDatabaseHelper.getWritableDatabase();
}
return mDatabase;
}
public synchronized void closeDatabase() {
mOpenCounter--;
if (mOpenCounter == 0) {
// Closing database
mDatabase.close();
}
}

}

有谁知道问题可能是什么?

干杯!

切勿使用来自多个线程的同一SQLiteDatabase对象,因为一个连接只能有一个事务。

此外,必须将query/update/insert调用包装到单个事务中,以防止其他线程在两者之间修改数据库。

是的。所以这不是一个多线程问题。嗯,是的,但不是真的。

我有这个查询:

static final String GET_VISIT_BY_REMOTE_ID = "SELECT " + TABLE_NAME + ".*" + ", " +
SHOPS.TABLE_NAME + "." + SHOPS.NAME + " AS " + SHOPS.TABLE_NAME + "_" + SHOPS.NAME +
" FROM " + TABLE_NAME +
" INNER JOIN " + SHOPS.TABLE_NAME + " ON " + TABLE_NAME + "." + REMOTE_SHOP_ID + "=" + SHOPS.TABLE_NAME + "." + SHOPS.REMOTE_OBJ_ID +
" WHERE " + TABLE_NAME + "." + REMOTE_OBJ_ID + " = ?";

问题是,在上述查询运行时,同步商店的另一个查询也在运行,实际上是多个查询。一个清除商店,另一个同步数据。因此,有时,即使 delete+sync_shop 查询紧接一个,位于单独的线程中,删除查询也会首先运行,然后运行上面的查询(它没有找到商店,所以查询失败,即使它有访问返回(,然后它才用数据重新填充商店。

基本上我正在删除数据,检查它是否存在(来自另一个线程(,然后填充数据,但为时已晚,因为另一个线程已经完成。

最新更新