2011-06-03 60 views
6

請考慮以下內容:我有Service,它在AsyncTask中寫入數據庫。我的Activity從數據庫讀取數據(爲簡單起見,考慮UI線程)。我使用SQLiteOpenHelper訪問數據庫。我在Application onCreate()中創建單個實例,然後在服務和活動中獲取它。有沒有可能讓我的數據庫'死鎖'?以前,我使用ContentProvider進行這些操作。雖然它基於使用單個的SQLiteOpenHelper實例,但我決定通過排除ContentProvider來簡化我的項目。從多個線程訪問的SQLite數據庫

考慮代碼:

public class App extends Application { 

    private OpenHelper openHelper; 

    @Override 
    public void onCreate(){ 
     super.onCreate(); 
      openHelper=new OpenHelper(); 
    } 

     public OpenHelper getHelper(){ 
      return openHelper; 
     } 
} 

在活動時間:

OpenHelper helper=(App)getApplication().getHelper(); 
SQLiteDatabase db=helper.getReadableDatabase(); 
// Do reading 

而且裏面的貢獻莫過於,在單獨的線程:

OpenHelper helper=(App)getApplication().getHelper(); 
SQLiteDatabase db=helper.getWritableDatabase(); 
//Do writing 

難道是安全的?

UPDThis可能是解決方案,但不知道如何使用它。

回答

0

好問題。我的第一個想法是它不安全。但是,根據SQLite docs,SQLite可以在3種模式下使用。默認模式是「序列化」模式:

序列化。在串行模式,SQLite的 可以安全地使用多線程 沒有限制

所以我認爲這是在Android上的序列化模式進行編譯。

2

我的投注:這是不安全的。

要處於更安全的位置,您應該使用SQL事務。從beginTransaction()beginTransactionNonExclusive()開始,並以endTransaction()結束。 Like shown here

+0

beginTransactionNonExclusive()給我錯誤,它爲上面的api11。但我的應用程序min api是10.任何其他方式使用sqlite與IMMEDIATE模式? – 2013-10-02 13:29:52

1

這是我的解決方案 我創建了一個類和私有靜態對象syncronize所有DB訪問

public class DBFunctions { 
// ... 
private static Object lockdb = new Object(); 


/** 
* Do something using DB 
*/ 
public boolean doInsertRecord(final RecordBean beanRecord) { 
    // ... 
    boolean success = false; 

    synchronized (lockdb) { 
       // ... 
       // 
       // here ... the access to db is in exclusive way 
       // 

       // ... 
     final SQLiteStatement statement = db.compileStatement(sqlQuery); 

     try { 
      // execute ... 
      statement.execute(); 
      statement.close(); 

      // ok 
      success = true; 
     } catch (Exception e) { 
      // error 
      success = false; 
     } 
      } 

     return success; 
    } 

}

我使用異步任務tryed,它工作正常。 我希望是解決問題的正確方法。

其他建議???

+0

同時運行三個AsyncTasks,全部插入許多行到一個表中。 (全部寫入同一張表)看起來任務隊列並且因此沒有錯誤被拋出。這個解決方案適用於我。我仍然想知道這個解決方案是否是死鎖安全的。有什麼意見? – BenjaminButton 2013-10-10 10:17:24

+0

經過一些更多的測試數據庫鎖定錯誤再次出現... – BenjaminButton 2013-10-10 10:45:18

0

剛看到這個,而我正在尋找別的東西。 此問題看起來像使用ContentProvider可以有效解決。這樣,活動以及服務都可以使用內容提供者,並將處理Db爭用問題。

7

遲到,遲到的答案。你完全沒問題。實際上,這是正確的做法。看我的博客文章:http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection/。在這裏挖掘我的個人資料。很多這樣的例子。除非您在應用程序之外共享數據,否則ContentProvdier只是很大的開銷,並不需要。事務處理很好地加速了事件並(顯然)提高了一致性,但並不需要。

只需在您的應用中使用一個SqliteOpenHelper,您就安全了。

+0

博客文章關閉 – seb 2012-09-24 23:28:04

+0

@seb編輯答案。幾個月前移動了博客。也看看sqlite鎖定帖子:http://touchlabblog.tumblr.com/post/24474398246/android-sqlite-locking。他們在這裏的關鍵是Android在Java-land中爲你做了線程鎖定,但只在單個實例上。多個會打破對方。另外,在文章中說,在UI線程中進行數據庫讀取。請注意:不要這樣做。永遠。 – 2012-09-26 04:53:55

+0

@KevinGalligan我已經挖掘了SQLiteDatabase和Helper的源代碼,我相信你錯了。 Database對象創建一個SQLiteStatement對象,該對象又使用SQLiteSession,每個線程都將擁有自己的SQLiteSession。它特別在SQLiteSession中說javadoc類不是線程安全的。好奇是什麼讓你說這個,因爲我真的希望你是對的... – schwiz 2013-10-13 18:31:29