2014-10-06 23 views
0

我正在使用greenDAO作爲數據持久層的Android應用程序。應用程序通過多個線程(由線程池確定)從各種不同源下載數據,每個數據片段都使用insertOrReplaceInTx在事務中插入到數據庫中。這工作正常。您可以使用greenDAO將不同線程中的多個嵌套事務封裝到整個事務中嗎?

我的問題是使用greenDAO技術是否可能使用嵌套事務將這些不同事務(發生在不同線程上)封裝到整個事務中。從理論上講,如果所有交易都是在一個線程上進行的話,我可以做到這一點,但我不確定在不同的線程上是否可能發生insertOrReplaceInTx調用。

我希望將這些封裝到單個整體事務中的原因是因爲它們表示應用程序內的同步過程。如果任何單一部分導入失敗,我希望中止並回滾整個交易中的所有修改。

如果我在啓動導入過程的主線程上開始與db.beginTransaction的事務,則當另一個線程嘗試insertOrReplaceInTxt時,會產生死鎖。

正確的方法來解決這個問題,以確保所有greenDAO事務都發生在同一個線程上?

回答

1

Afaik,你不能因爲每個線程管理自己的連接。

如果您在這些操作之間有這種依賴關係,那麼您可能想同步它們。

例如如果作業A在作業B和作業B的數據庫連接失敗之前完成,該怎麼辦?您的數據將不再同步。你還需要其他工作的邏輯。 另外,作家是互斥的。

我會建議創建一個可以在事務中運行runnables列表的實用程序類。每個作業完成後,將一個Runnable排入此實用程序。這些可運行的程序包括實際的數據庫命令。

當最後一個到達(這取決於您的依賴性邏輯)時,該實用程序將運行事務中的所有可運行參數。

示例實現可能是這樣的:(我用一個簡單的計數器,但是你可能需要一個更復雜的邏輯)

class DbBundle { 
    AtomicInteger mLatch; 
    List<Runnable> mRunnables = new ArrayList(); 
    DbBundle(int numberOfTx) { 
     mLatch = new AtomicInteger(numberOfTx); 
    } 

    void cancel() { 
     mLatch.set(-1); // so decrement can never reach 0 in submit 
    } 

    boolean isCanceled() { 
     mLatch.count() < 0; 
    } 

    void submit(Runnable runnable) { 
     mRunnables.add(runnable); 
     if (mLatch.decrementAndGet() == 0) { 
      db.beginTransaction(); 
      try { 
       for (Runnable r : mRunnables) r.run(); 
       db.setTransactionSuccessful() 
      } finally { 
        db.endTransaction(); 
      } 
     } 
    } 
} 

當您創建的每個工作,你通過這個共享DbBundle,最後一個會全部執行它們。 因此,一份工作看起來像:

.... 
try { 
    if (!dbBundle.isCanceled()) { // avoid extra request if it is already canceled 
     final List<User> users = webservice.getUsers(); 
     dbBundle.submit(new Runnable() { 
      void onRun() { 
       saveUsers(users);//which calls db. no transaction code. 
      }); 
    }); 
} catch(Throwable t) { 
    dbBundle.cancel(); 
} 
+0

謝謝,我認爲這可能是要走的路。雖然我不太瞭解你對有關工作不同步的評論。我也許沒有提到每項工作本質上都是將寫入數據寫入不同的表中,除了所有這些工作都應該順利完成以成功完成同步之外,這些工作之間不存在依賴關係。如果作業B失敗,我會期望中止該過程並結束交易失敗。順便說一句,我使用的Android優先級作業隊列,我認爲你開發:) – jdmunro 2014-10-07 08:34:06

+0

哈,是的,這看起來像一個問題引起的解耦的東西:)。 你提到JobA和JobB應該都完成或者都失敗。即使使用數據庫事務(如果他們正在工作),您也需要阻止JobA直到JobB完成,這對Job線程沒有很好的使用(並且如果依賴作業數量大於最大消費者數量,將會死鎖)。也許我們可以將它作爲JobManager的擴展。我一直在想這些有用的擴展工作。如果你碰巧寫了一個通用的請求,隨意發送一個拉取請求。 – yigit 2014-10-08 04:08:12

+0

我仍然不確定是否需要阻止JobA(我認爲我誤解了某些東西!)。讓我們說JobA下載一些實體並將它們插入到數據庫中。與JobB中下載的數據沒有任何關係。同時,JobB下載它的實體並將它們插入到數據庫中。 AFAIK,greenDAO確保對數據庫的串行訪問。因此,讓我們說我們確實有一些方便的方法將所有這些封裝到整個事務中。如果JobA失敗,我們將中止這個整體交易,並取消JobB。這不會確保DB數據的原子性,而無需同步作業? – jdmunro 2014-10-08 11:09:43