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

Gra*_*and 29 sqlite android android-webview

我有一个只读数据库连接.有时,当使用SELECT查询从数据库中读取数据时,它会抛出一个SQLiteReadOnlyDatabaseException.

我这样打开连接:

return SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
Run Code Online (Sandbox Code Playgroud)

查询是:

Select * FROM BudgetVersions WHERE entityId = ?
Run Code Online (Sandbox Code Playgroud)

我使用数据库读取数据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();
}
Run Code Online (Sandbox Code Playgroud)

很少,我在这样的调用中遇到了这样的崩溃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)
Run Code Online (Sandbox Code Playgroud)

作为一种解决方法,我可以尝试使用可写数据库连接,但我想知道崩溃发生的原因.

我正在阅读的表是一个标准的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
);
Run Code Online (Sandbox Code Playgroud)

我已经看到崩溃发生在KitKat仿真器和运行Lollipop的设备上.


有一个独立的可写连接打开到同一数据库在同一时间,一个拥有web视图.数据库正在由WebView中的Javascript代码更新,并使用此只读连接从本机Android/Java层读取.

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

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

Gra*_*and 17

通过将其更改为可写数据库连接来解决.线索在776错误代码文档中:

(776)SQLITE_READONLY_ROLLBACK

SQLITE_READONLY_ROLLBACK错误代码是SQLITE_READONLY的扩展错误代码.SQLITE_READONLY_ROLLBACK错误代码表示无法打开数据库,因为它有一个需要回滚的热日志,但由于数据库是只读的而无法打开.

在开发过程中,我经常打断当前正在运行的应用程序以安装和运行新版本.这会导致当前正在运行的应用程序被系统强制停止.如果WebView中的Javascript代码在应用程序被破解时通过其单独的可写连接写入数据库,那么热门日志将被遗忘.

当新版本的应用程序启动时,将打开本机Java代码中的只读数据库连接.当此连接发现日志时,它会尝试回滚期刊.因为它是只读连接,所以它失败了.

(这与我在做出改变后立即在启动时观察到的崩溃相吻合.)

因此,正确的解决方法是使Java连接成为可写连接.此连接在正常操作期间从不尝试写入,但必须在通过WebView的可写连接从先前中断的写入中恢复时进行写入.

  • 嗨格雷厄姆,你能指导我如何使Java连接成为可写的吗?谢谢 (4认同)