2015-05-06 36 views
26

我有一個只讀的數據庫連接。有時,當用SELECT查詢從數據庫中讀取數據時,它會拋出SQLiteReadOnlyDatabaseException嘗試寫只讀數據庫...但我不是

我開這樣的連接:

return SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY); 

查詢是:

Select * FROM BudgetVersions WHERE entityId = ? 

我使用db.rawQuery()從數據庫中讀取數據,就像這樣:

String query = ...; 
Cursor c = db.rawQuery(query, new String[]{ activeBudgetId }); 
try { 
    if (c.moveToFirst()) {    
     bv.versionName = c.getString(c.getColumnIndexOrThrow("versionName")); 
     return bv; 
    } else { 
     return null; 
    } 
} finally { 
    c.close(); 
} 

非常罕見,我得到了這樣的崩潰,在撥打電話c.moveToFirst()

Caused by: android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 776) 
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method) 
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:845) 
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836) 
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62) 
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:144) 
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133) 
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197) 
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:237) 

作爲一種解決方法,我可以嘗試使用可寫的數據庫連接,但我想知道爲什麼崩潰正在發生。

我從閱讀該表是一個標準的SQLite表:

CREATE TABLE BudgetVersions (
    entityId  VARCHAR PRIMARY KEY NOT NULL UNIQUE, 
    budgetId  VARCHAR NOT NULL, 
    versionName  VARCHAR NOT NULL, 
    dateFormat  VARCHAR, 
    currencyFormat VARCHAR, 
    lastAccessedOn DATETIME, 
    isTombstone  BOOL  NOT NULL, 
    deviceKnowledge NUMERIC NOT NULL 
); 

我見過的碰撞發生在既有奇巧模擬器運行棒棒糖的裝置。


有一個單獨寫開到同一個數據庫同時連接,由web視圖擁有。數據庫正在通過WebView中的Javascript代碼進行更新,並使用此只讀連接從本機Android/Java層讀取。

我希望這可能被證明是問題的根本原因,但我想詳細瞭解爲什麼只讀連接會干擾單獨的可寫連接。

我知道一般的建議是使用單一連接到數據庫,但由於可寫連接歸WebView所有,所以我不能從Java代碼中輕鬆訪問它。

+0

請注意,'cwac-loaderex'已停用相當長一段時間。這是您在開發過程中看到的崩潰,還是僅在生產過程中看到的?請注意,'getCount()'實際上是在執行你要加載器加載的SQL查詢,因爲'rawQuery()'/'query()'返回一個'Cursor',但不會立即執行查詢。 – CommonsWare

+0

刪除了裝載機和CWAC-LoaderEx的提及。如果沒有他們,問題也會發生。在開發過程中發生崩潰。 –

+0

我會說這是sqlite如何根據標誌返回數據庫實例的一個bug,可能與多線程相關。我會假設試圖爲你的所有操作保存一個可讀寫數據庫的單例實例應該解決它(也打開你所有的讀寫連接) – njzk2

回答

15

通過將其更改爲可寫數據庫連接來解決。線索是在documentation for the 776 error code

(776)SQLITE_READONLY_ROLLBACK

的SQLITE_READONLY_ROLLBACK錯誤碼是用於 SQLITE_READONLY擴展錯誤代碼。 SQLITE_READONLY_ROLLBACK錯誤代碼表示 數據庫無法打開,因爲它有一個熱日誌, 需要回退但不能打開,因爲數據庫是隻讀的。

在開發過程中,我經常中斷正在運行的應用程序來安裝並運行新版本。這會導致當前正在運行的應用程序被系統強制停止。如果WebView中的Javascript代碼在應用程序被刪除時正在通過其單獨的可寫連接寫入數據庫,那麼hot journal將被留下。

當新版本的應用程序啓動時,打開本地Java代碼中的只讀數據庫連接。當這個連接發現日誌時,它試圖回滾日誌。並且因爲它是隻讀連接,所以它會失敗。

(這符合立刻被觀察到在啓動時崩潰,我做了更改後。)

正確的修改,因此是使Java的連接可寫連接。此連接在正常操作期間從不嘗試寫入,但在通過WebView的可寫連接從先前中斷的寫入恢復時必須寫入。

+4

嗨Graham,你能指導我如何使Java連接成爲可寫的連接嗎?謝謝 – user219882

+0

返回SQLiteDatabase.openDatabase(path,null,SQLiteDatabase.OPEN_READWRITE); – ketom

相關問題