我遇到了rawQuery
的问题。有时候它没有按照ID找到一个项目,而有时却没有。
我的逻辑如下:我从Web服务中检索一些数据。我将它与本地数据库同步,然后我从本地数据库(而不是从我从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()
为false,因此它会插入一个新项而不是更新它。
在UI线程上,20个调用正常工作,他们不会创建新项目...但是我最近将上述方法的调用移动到了非UI线程,并且#39从那以后它就开始表现了。我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();
}
}
}
有谁知道问题可能是什么?
干杯!
答案 0 :(得分:1)
您绝不应该使用来自多个线程的相同SQLiteDatabase
对象,因为一个连接只能有一个事务。
此外,您必须将query
/ update
/ insert
调用包装到单个事务中,以防止其他线程在其间修改数据库。
答案 1 :(得分:0)
呀。所以这不是一个多线程问题。嗯,确实如此,但事实并非如此。
我有这个问题:
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查询紧跟在一起,处于不同的线程中,删除查询将首先运行,然后是上面的查询(没有查找商店,所以查询失败,即使它有访问返回),只有这样它才会重新填充商店的数据。
基本上我是删除数据,检查它是否存在(来自另一个线程)然后填充数据,但是由于另一个线程已经完成,所以太晚了。