尝试写一个只读数据库...但我不是

时间:2015-05-06 16:06:51

标签: android sqlite android-webview

我有一个只读数据库连接。有时,当使用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
);

我发现KitKat仿真器和运行Lollipop的设备都发生了崩溃。

单独的可写连接打开到同一个数据库同时,由WebView拥有。数据库正在通过WebView中的Javascript代码进行更新,并使用此只读连接从本机Android / Java层中读取。

我希望这可能是问题的最终原因,但我想详细了解为什么只读连接会干扰单独的可写连接。

我很清楚,一般的建议是使用与数据库的单一连接,但由于可写连接由WebView拥有,因此我无法从Java轻松访问它代码。

1 个答案:

答案 0 :(得分:16)

通过将其更改为可写数据库连接来解决。线索在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的可写连接从先前中断的写入中恢复时进行写入。