2017-07-19 8 views
0

rawQueryに問題があります。他の時にIDで項目を見つけられないことがあります。rawQueryでデータベース内の項目が見つからないことがあります(マルチスレッドの問題)

私のロジックは次のとおりです:私はWebサービスからいくつかのデータを取得します。私はそれをローカルデータベースと同期させてから、私はローカルデータベースから(私がウェブサービスから受け取ったものではなく)ユーザーに応答を返します。

私の問題は、私がデータを同期させるときに、rawQueryがローカルデータベースからアイテムを取り出して、すでにそれがあるかどうかを確認することです。見つからない場合は新しい行が挿入され、存在する場合は更新されます。ここでの方法です:それはそれを更新するのではなく、新しい項目を挿入して、私は矢継ぎ早とc.moveToFirst()が偽である当時のいくつかでは、行に20回(ちょうどデバッグの目的のために)、このメソッドを呼び出してみました

@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; 
} 

、 。

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(); 

    } 
} 

}

は、誰もが問題が何であるか知っていますか?

乾杯!

答えて

1

1つの接続で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 + " = ?"; 

は、上記のクエリの実行中に、お店を同期化別のクエリが実際複数のクエリでは、同様に動作していたということです。

私はこのクエリを持っていました。 1つは店舗を清算し、もう1つはデータを同期させたものです。だから時々、delete + sync_shopのクエリが別々のスレッドの中にあっても、deleteクエリが最初に実行され、次に上記のクエリが実行されます(ショップを見つけられなかったのでクエリが失敗したとしてもそれは戻ってくる訪問を持っていた)、それだけで店でデータを再投入した。

基本的に私はデータを削除して、別のスレッドから存在するかどうかをチェックしてデータを取り込みましたが、もう一方のスレッドが既に終了しているので遅すぎます。

関連する問題