2011-10-28 58 views
27

我收到以下錯誤。那麼如何解鎖我的數據庫呢?Android數據庫鎖定

10-28 08:43:26.510: ERROR/AndroidRuntime(881): FATAL EXCEPTION: Thread-11 
10-28 08:43:26.510: ERROR/AndroidRuntime(881): android.database.sqlite.SQLiteDatabaseLockedException: database is locked 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.database.sqlite.SQLiteDatabase.dbopen(Native Method) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:983) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:956) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1021) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:742) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:149) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at com.aa.me.vianet.dbAdapter.DbAdapter.open(DbAdapter.java:25) 
10-28 08:43:26.510: ERROR/AndroidRuntime(881):  at com.aa.me.vianet.services.NotificationManagerThread.run(NotificationManagerThread.java:49) 
+0

1.確保您只在同一個文件上使用單個SQLiteOpenHelper。 2。確保一次只有一個線程正在使用您的SQLiteDatabase。 – Jens

回答

32

我想你已經忘記關閉數據庫,或當你試圖寫它另一個線程寫入數據庫。 SQLite在寫入數據庫時​​會鎖定數據庫,以防止另一個實體嘗試同時寫入同一數據庫時發生損壞。 Android的,將只顯示在日誌貓錯誤,你提供的將只是忘記了查詢...

所以,我建議:

  • 你只從一個SQLOpenHelper
  • 您訪問數據庫請確保您關閉數據庫助手的所有實例,一旦你與他們完成
  • 你要確保你總是最後交易與endTransaction()如果你還沒有設置他們獲得成功(也就是說,如果你想EM滾」回去),如果你使用交易
  • 你可以嘗試使用OrmLite,我沒有使用它,但我聽說過其他人在這裏狂喜。
+5

我寫了OrmLite的原始端口到Android。你的第一個建議,只使用一個幫手,是很好的建議。你的第二個與你的第一個矛盾。 「關閉數據庫幫助程序的所有實例」意味着超過1.僅使用一個,始終!另外,你不需要關閉你的助手連接。請看我的答案。最初,我爲OrmLite編寫了複雜的引用計數代碼,以幫助保持一個助手的存活狀態,並在完成後關閉它,但事實證明,Sqlite「連接」只是文件句柄。系統將在轉儲過程時爲您關閉它們。 –

+0

嘿凱文,這是否意味着你永遠不必關閉你的數據庫處理程序? –

+2

是的。我知道這聽起來很糟糕。處理程序只是一個文件句柄。當過程死亡時它將關閉。 SQLite不會破壞自己。至於只在logcat中顯示錯誤,對於「插入」而言是如此,但對於其他方法而言則如此。這就是爲什麼你應該總是調用「insertOrThrow」。 –

7

出現這種情況的原因是因爲你只能有一次一個連接到數據庫的打開(這是爲了防止競爭條件修改數據庫時)。我猜你多次連接到不同線程的數據庫?解決這個問題的最簡單方法就是爲您的數據庫創建一個ContentProvider前端。這將能夠處理來自多個線程的查詢。

欲瞭解更多信息,結賬這個blogpost

+0

blogpost的鏈接中斷,新的鏈接又破了http://www.touchlab.co/blog/android-sqlite-locking/ – pengwang

+0
+0

@christophercotton似乎再次爲我工作。 –

11

使用您整個應用程序的單一連接。在這裏看到:

http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection

+0

你能修復這個鏈接嗎?如何處理多線程訪問與單一連接? – Michael

+0

@邁克爾固定鏈接! –

+0

我用這種方法,但不工作在我的情況請看看我的問題[鏈接在這裏...](http://stackoverflow.com/questions/13859840/application-crashes-on-installation -with-error-sqlite3-exec-failed-set-sync) – MobileEvangelist

0

我有一個類似的錯誤。我的問題是,我不小心給了兩個助手類的數據庫相同的名稱,所以他們最終同時訪問了同一個數據庫。所以確保你沒有使用多個helper類訪問單個數據庫。

2

我有同樣的問題,請嘗試使用此

db.beginTransactionNonExclusive(); 
    try { 
     //do some insertions or whatever you need 
     db.setTransactionSuccessful(); 
    } finally { 
     db.endTransaction(); 
    } 

我試着用db.beginTransaction但它鎖定了BD

0

我有同樣的問題,因爲我試圖通過訪問我的數據庫ContentResolver雖然我已經有一個直接打開SQLiteDatabase連接(交易所需)。

我通過更改我的代碼的順序來解決它,所以ContentResolver的東西是在我的直接SQLiteDatabase連接打開之前完成的。

我還刪除了一些代碼,所以我不再接近我的直接SQLiteDatabase

這是值得一讀this answer,因爲它提供了很多其他有用的指導。