会议室数据库:RoomOpenHelper.checkIdentity()

时间:2018-02-16 01:09:15

标签: android sqlite android-room android-architecture-components

我有一个遗留应用程序正在使用Room,一旦执行第一个数据库查询就会崩溃,无论查询是什么。

  java.lang.RuntimeException: Unable to start service com.someco.android.nettasks.PushQueueService@24ccdca6 with Intent { cmp=com.someco.android/.nettasks.PushQueueService }: android.database.sqlite.SQLiteException: Cannot execute this statement because it might modify the database but the connection is read-only.
      at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3439)
      at android.app.ActivityThread.access$2200(ActivityThread.java:181)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1572)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:145)
      at android.app.ActivityThread.main(ActivityThread.java:6117)
      at java.lang.reflect.Method.invoke(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:372)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
   Caused by: android.database.sqlite.SQLiteException: Cannot execute this statement because it might modify the database but the connection is read-only.
      at io.requery.android.database.sqlite.SQLiteConnection.throwIfStatementForbidden(SQLiteConnection.java:1091)
      at io.requery.android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:755)
      at io.requery.android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:764)
      at io.requery.android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:71)
      at io.requery.android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1867)
      at io.requery.android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1808)
      at android.arch.persistence.room.RoomOpenHelper.createMasterTableIfNotExists(RoomOpenHelper.java:131)
      at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:107)
      at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
      at io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory$CallbackSQLiteOpenHelper.onOpen(RequerySQLiteOpenHelperFactory.java:67)
      at io.requery.android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:283)
      at io.requery.android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:174)
      at io.requery.android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:44)
      at com.someco.android.dmodel.OurDB.writableDb(OurDB.java:363)
      at com.someco.android.nettasks.PushQueueService.startExecution(PushQueueService.java:202)
      at com.someco.android.nettasks.PushQueueService.onStartCommand(PushQueueService.java:157)
      at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3422)
      at android.app.ActivityThread.access$2200(ActivityThread.java:181)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1572)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:145)
      at android.app.ActivityThread.main(ActivityThread.java:6117)
      at java.lang.reflect.Method.invoke(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:372)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

根据我对调试器的调查,发生的事情是,在sqlite本身调用sqlite3_stmt_readonly()方面存在某种竞争问题。这是导致崩溃的实际查询,来自RoomOpenHelper#createMastertableIfNotExists

CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)

RoomOpenHelper#onCreate中,表格已成功创建。一个语句似乎被编译了两次,并检查了两次只读状态:

  • 进入SQLiteProgram的构造函数(通过SQLiteStatement
  • 进入SQLiteConnection#executeForChangedRowCount

所发生的情况是,为第一个获取的连接以更宽松的权限打开(6,对我来说 - 1是表示只读状态的位),并且它已正确评估不是只读的。这意味着请求第二个语句编译的连接使用只读标志(5,对我而言)。发生崩溃是因为出于某种原因,查询被评估为不再是只读的。

我完全失去了这个。为什么会崩溃?相同的语句有时是只读的,而其他时候不是只读的吗?

1 个答案:

答案 0 :(得分:1)

问题是房间TimeCreationOf(() => new ClassTwo(), c => { c.SomeProperty = "x"; c.DoSomethingElse(); }); 不支持预写日志。我删除了在应用中启用它的行:

1.0.0

版本db.getOpenHelper().setWriteAheadLoggingEnabled(true); 支持WAL。尝试新的alpha后,一切正常,所以更改日志指出了答案。我已经example project对该问题进行了简要的记录。