【问题标题】:Reopen ROOM database重新打开 ROOM 数据库
【发布时间】:2018-12-27 12:18:19
【问题描述】:

我正在尝试关闭然后重新打开 Room 数据库。 (目的是备份SQLite文件)

这就是我关闭它的方式:

public static void destroyInstance() {
    if (INSTANCE != null && INSTANCE.isOpen()) {
        INSTANCE.close();
    }
    INSTANCE = null;
}

INSTANCE 是一个 RoomDatabase 对象

要重新打开,我将通过调用再次初始化 INSTANCE 对象:

Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, C.ROOM_DB_NAME)

在我转移到另一个活动后,我在 logcat 中看到了这个错误:E/ROOM: Invalidation tracker is initialized twice

SELECT 查询工作正常,但 INSERT 失败并出现以下错误:

E/SQLiteLog: (1) no such table: room_table_modification_log

E/ROOM: Cannot run invalidation tracker. Is the db closed?
java.lang.IllegalStateException: The database '/data/user/0/ro.example.example/databases/mi_room.db' is not open.

虽然 INSTANCE.isOpen() 返回 true

房间版本:1.1.1

有人知道这个“room_table_modification_log”表是什么吗?

【问题讨论】:

  • 您找到解决方案了吗?我在 Room 2.2.5 中仍然遇到此错误。
  • 没有解决办法。我只是不再关闭数据库。如果要将DB文件复制到其他位置,可以查看下面的答案(schv09的答案)
  • @MickeyR 你有解决办法吗,我也遇到这个错误
  • @AlexBusuioc 的任何解决方案我在 2.3.0 版中遇到此错误
  • 没有重新打开以前关闭的房间数据库的解决方案。我只是不再关闭数据库。检查@schv09 的答案或这个问题可能会有所帮助:stackoverflow.com/questions/50987119/backup-room-database

标签: android android-sqlite android-room


【解决方案1】:

花了这么多天终于找到了解决办法,需要在onOpendb回调中创建表room_table_modification_log

如下:

private fun buildDatabase(context: Context): MainDatabase {
            return Room.databaseBuilder(
                context.applicationContext,
                MainDatabase::class.java,
                databaseName
            ).addMigrations(MIGRATION_2_3)
                .addCallback(getCallback())
                .build()
        }

并像这样实现getCallback() 函数:

fun getCallback(): Callback {
    return object : Callback() {
        override fun onOpen(db: SupportSQLiteDatabase) {
            super.onOpen(db)
                db.execSQL("CREATE TEMP TABLE room_table_modification_log(table_id INTEGER PRIMARY KEY, invalidated INTEGER NOT NULL DEFAULT 0)")          
            }
        }
}

完成以上操作后你将无法得到错误room_table_modification_log

【讨论】:

    【解决方案2】:

    对于未来的读者:您无需关闭数据库即可将文件复制到另一个位置(创建备份)。

    SQLite 数据库的 Android 实现通常处于 WAL (write-ahead log) 模式。这在后台使用 3 个文件:第一个带有数据库名称(即 my_db,第二个带有该名称和“-shm”后缀(my_db-shm),第三个带有“-wal”后缀 (my_db-wal)。-wal 文件将保存更改。

    如果您想使用数据库的正常路径(my_db 文件)进行备份,您需要确保它是最新的最新事务。您可以通过在数据库上运行检查点来执行此操作。在此之后,您可以将此文件复制到手机上所需的位置,然后继续使用您的数据库而不会出现问题。 this question 上接受的答案很好地解释了这一点:

    但是如果将所有内容都移到原始数据库文件中 想做的话就不用关闭数据库了。

    你可以强制 使用wal_checkpoint pragma 代替检查点。查询 以下针对数据库的语句。我们在这里使用原始查询 因为 Room 尚不支持pragma(它将触发UNKNOWN query type error)。

    在你的 DAO 中有这个查询:

    @RawQuery
    int checkpoint(SupportSQLiteQuery supportSQLiteQuery);
    

    然后当你 调用检查点方法,然后使用查询:

    myDAO.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)"));
    

    【讨论】:

    • 很好的答案!但是,如果我想在检查点之后清除当前数据库并将数据库基本文件复制到存储中会发生什么?我使用 rxjava - 并且不能保证,某些线程不应该在“检查点”和“复制 DB”函数之间向数据库写入一些东西,因此,我不确定,我不清理不清理的数据移动到存储。你怎么看?谢谢!
    • UPD:我认为,我应该在 beginTransaction() 和 endTransaction() 块中使用此操作,不使用 DAO,使用原始“查询”(因为 DAO 将所有内容包装在 begin/endTransaction() 中 - 和在这种情况下不是这样),你怎么看,我是对的?
    • 很抱歉,dr_begemot,但由于我不使用 rxjava,所以在这里我无法为您提供帮助。希望您尽快找到解决方案!
    【解决方案3】:

    将您的 Room 版本降级到 1.1.1-rc1,问题就会消失。请留意更新,因为这是 1.1.1 中的错误

    【讨论】:

    • 刚刚测试过。不,这并不能解决问题。完全相同的行为
    • 我记得有同样的问题。这篇文章为我和其他人解决了这个问题stackoverflow.com/questions/50370683/…
    • 确实,这两个问题似乎是相关的。它们出现的上下文不同(在我的情况下关闭 - 重新打开数据库;在其他帖子的情况下进行数据库迁移)。不幸的是,我的问题出现在所有 Room 版本上
    猜你喜欢
    • 2020-09-13
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多