【问题标题】:Room cannot verify the data integrityRoom 无法验证数据完整性
【发布时间】:2017-10-27 02:18:04
【问题描述】:

我在使用 Room Database 运行程序时遇到此错误

Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. 
You can simply fix this by increasing the version number.

似乎我们需要更新数据库版本,但我们可以在 Room 中从哪里进行更新?

【问题讨论】:

  • 如果您不关心应用程序的数据,从应用程序设置中删除所有内容也可能会有所帮助,因为它只会破坏整个数据库

标签: android android-database android-room


【解决方案1】:

当您第一次看到此消息时,您很可能正在使用未发布的数据库版本。如果是这种情况,很可能您不应该增加数据库版本。只需清除应用数据即可让您通过异常。

如果不增加数据库(推荐):

您应该从 Android 设置中清除应用程序的应用数据。您也可以卸载以前的应用程序版本,然后安装新版本以通过异常。后一种方法在某些情况下不起作用(例如启用允许备份时)

由于清除应用程序数据总是有效的,所以我每次都走这条路。

如果您确实增加了数据库版本:

您需要编写数据库迁移代码来说明对数据库架构的任何更改。有关迁移的信息,请参阅 here

编写数据库迁移代码的替代方法是在 Room 数据库构建器上调用 fallbackToDestructiveMigration。这可能不是一个好主意。忘记删除这个调用然后忘记升级数据库会导致数据丢失。

// Using this fallback is almost certainly a bad idea
Database database = Room.databaseBuilder(context, Database.class, DATABASE_NAME)
        .fallbackToDestructiveMigration()
        .build();

再次强调,如果之前的数据库架构不存在在野外,则不需要增加数据库版本或回退到破坏性迁移。

【讨论】:

  • 我希望他们为这种情况包括另一种后备方法:(
  • 在 Room 的 1.0.0-rc1 版本中,唯一对我有用的是增加数据库版本。
  • 我的 AndroidManifest.xml 中有 android:allowBackup="true",即使在卸载应用程序后也无法清除数据。我将此属性设置为 false,然后重新安装了应用程序,这有助于解决问题。注意,true是allowBackup的默认值,所以如果你根本不使用它,它仍然可能导致数据被保留。
  • @Bartek 这个评论现在值得回答了。
  • 卸载应用对我有用,谢谢!
【解决方案2】:
AndroidManifest.xml 中的

android:allowBackup="true" 可防止在卸载应用后清除数据。

将此添加到您的清单中:

android:allowBackup="false"

并重新安装应用程序。

注意:如果您想要自动备份,请确保稍后将其更改回 true。

另一种解决方案:

检查旧 json 文件的 identityHash 和 apps\schema 文件夹中的新 json 文件。

如果identityHash不同,就会报错。如果您不想更改任何内容,请通过比较两个 json 文件找出您更改的内容。

确保您有 exportSchema = true。

@Database(entities = {MyEntity.class, ...}, version = 2, exportSchema = true)

json 架构文件:

  "formatVersion": 1,
  "database": {
    "version": 2,
    "identityHash": "53cc5ef34d2ebd33c8518d79d27ed012",
    "entities": [
      {

代码:

private void checkIdentity(SupportSQLiteDatabase db) {
    String identityHash = null;
    if (hasRoomMasterTable(db)) {
        Cursor cursor = db.query(new SimpleSQLiteQuery(RoomMasterTable.READ_QUERY));
        //noinspection TryFinallyCanBeTryWithResources
        try {
            if (cursor.moveToFirst()) {
                identityHash = cursor.getString(0);
            }
        } finally {
            cursor.close();
        }
    }
    if (!mIdentityHash.equals(identityHash) && !mLegacyHash.equals(identityHash)) {
        throw new IllegalStateException("Room cannot verify the data integrity. Looks like"
                + " you've changed schema but forgot to update the version number. You can"
                + " simply fix this by increasing the version number.");
    }
}

【讨论】:

    【解决方案3】:

    默认情况下,Android 清单具有android:allowBackup="true",它允许应用在重新安装时保留其 SQLite 数据库。

    假设您的 DATABASE_VERSION 最初是 3,然后您决定将 DB 版本从 3 减少到 1。

    @Database(entities = {CallRecording.class}, version = DATABASE_VERSION)
    public abstract class AppDatabase extends RoomDatabase {
        public abstract RecordingDAO recordingDAO();
    
    //    static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    //        @Override
    //        public void migrate(SupportSQLiteDatabase database) {
    //            // Since we didn't alter the table, there's nothing else to do here.
    //        }
    //    };
    }
    

    你可以这样实现

    • 从设置中清除应用数据。这将从手机中删除旧的 DB(DATABASE_VERSION =3)
    • 卸载您的应用程序
    • 将 DATABASE_VERSION 版本降低到 1
    • 构建并重新安装您的应用程序

    保持DATABASE_VERSION 不变是一个好习惯。

    【讨论】:

    • 会不会影响从Play商店更新应用的用户?
    • 我也按照同样的方法,但是没有用。即使我试图从 Android Studio 安装在新设备上,它也会显示相同的错误:x
    • @nimi0112 对于您的发布版本,您应该允许备份,但是对于您的调试版本,您可以将其关闭
    【解决方案4】:

    Aniruddh Parihar 的回答给了我一个提示,它解决了。

    搜索您扩展了RoomDatabase 的类。在那里你会找到如下版本:

    @Database(entities = {YourEntity.class}, version = 1)
    

    只要增加版本,问题就解决了。

    【讨论】:

      【解决方案5】:

      非常简单,如日志所示

      Looks like you've changed schema but forgot to update the Database version number. 
      You can simply fix this by increasing the version number.
      

      简单地转到您的数据库版本类并通过从当前增加 1 来升级您的数据库版本。

      例如:在您的项目中找到@Database 注释,如下所示

      @Database(entities = {YourEntityName.class}, version = 1)
      

      这里的version = 1,是数据库版本,你只需要增加它 一,就是这样。

      【讨论】:

      • 是的,我遇到了那个错误,这就是为什么我也提到了It seems we need to update database version。但我没有得到提到那个版本的地方。无论如何感谢您的提示。
      • 您已经改写了错误消息,但没有提供任何额外信息来解决原始发帖人的困惑。
      • @CarlRossman :你必须在你的项目中找到你的数据库类,你使用了数据库注释,在那个类上你会找到数据库版本(整数值),只需将它从当前增加一。
      【解决方案6】:

      1:- 看来我们需要更新数据库版本(增加1)

      第二次卸载应用或清除应用数据

      【讨论】:

        【解决方案7】:

        为了解决kotlin中的问题:

        第一

        @Database(entities = [Contact::class], version = 2)
        

        第二

        val MIGRATION_1_2 = object : Migration(1, 2) {
                override fun migrate(database: SupportSQLiteDatabase) {
                    database.execSQL("ALTER TABLE Contact ADD COLUMN seller_id TEXT NOT NULL DEFAULT ''")
                }
            }
        

        第三

        private fun buildDatabase(context: Context) = Room.databaseBuilder(
                    context.applicationContext,
                    EpayDatabase::class.java,
                    "epay"
                )
                    .addMigrations(MIGRATION_1_2)
                    .build()
        

        更多详情,请查看official documentation

        【讨论】:

          【解决方案8】:

          不要在生产代码中使用此解决方案!
          改用Aniruddh Parihar's answer,或peterzinho16's answer

          在安卓手机上:

          卸载应用清除应用数据

          要删除应用数据: 转到设置 -> 应用程序 -> 选择您的应用程序 -> 存储 -> 清除数据

          卸载(和重新安装)并非在所有情况下都有效,因此请先尝试清除数据!

          【讨论】:

          • 是的。但奇怪的是,我在刚刚完全擦除并重新设置的设备上遇到了这个问题。但是简单的清除数据就解决了。
          • 这不应该在生产环境中完成。您不应强制所有用户清除应用程序中的数据。最好通过将 Room 数据库中的版本增加 1 来编写迁移代码。
          • 就像@RajeevJayaswal 已经提到的那样,即使出于测试目的,这也是一个糟糕的主意。您应该改用迁移选项。
          【解决方案9】:

          在我的情况下,android:allowBackup="false" 将其从 true 变为 false 有效,因为这也让我做噩梦,这是最奇怪的事情,为什么默认启用此设置!

          【讨论】:

            【解决方案10】:

            这个问题主要发生在开发阶段。

            如果您更改架构,即重命名/添加/修改包含表实体的类,则先前构建中退出数据库之间的完整性与新构建冲突。

            清除应用数据卸载旧版本后安装新版本

            现在,旧数据库不会与新数据库冲突。

            【讨论】:

            • 之后还是崩溃
            • 有什么异常?请张贴日志以缩小问题范围。
            • 谢谢,现在一切正常。我阅读了android:allowBackup="true" 并明智地使用它
            • @user7856586 那么al​​lowBackup呢?能否请您用您的智慧启发我们?
            • @Ridcully 你可以读到here你为什么这么生气?
            【解决方案11】:

            在我的例子中,我在迁移中使用了一个事务,而 Room 无法使用迁移助手更新哈希

            @get:Rule
            val migrationTestHelper: MigrationTestHelper =
            
            MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                            C2GDatabase::class.java.canonicalName,
                            FrameworkSQLiteOpenHelperFactory()) 
            /* Testing method throws error*/
            db = migrationTestHelper.runMigrationsAndValidate(C2GDatabase.DB_NAME,
                        3,
                        false,
                        C2GDatabase.Migration_1_2(),
                        C2GDatabase.Migration_2_3())
            
            
            override fun migrate(database: SupportSQLiteDatabase) {
            
            /** 
                Error
                database.beginTransaction()
            **/
            database.execSQL("PRAGMA foreign_keys=off;")
            database.execSQL("ALTER TABLE user RENAME TO user_old;")
            database.execSQL("CREATE TABLE user ( id_user INTEGER PRIMARY KEY AUTOINCREMENT, external_id INTEGER NOT NULL;")
            database.execSQL("INSERT INTO user ( id_user, external_id ) " +
                                    " SELECT               id_user, external_id" +  
                                    " FROM                 user_old;")
            
            database.execSQL("CREATE UNIQUE INDEX idx_unique_user ON user (external_id);")
            database.execSQL("PRAGMA foreign_keys=on;")
            database.execSQL("DROP TABLE user_old;")
            //database.endTransaction() 
            }
            

            【讨论】:

            • 我挣扎了几个小时,这就是解决方案!谢谢!!
            • 在上面的例子中,问题不是事务。您忘记在结束之前设置事务成功:
               database.beginTransaction() database.setTransactionSuccessful() database.endTransaction() 
            【解决方案12】:

            就我而言,我有一个 AppDatabase 类。

            @Database(entities = {GenreData.class, MoodData.class, SongInfo.class,
                AlbumsInfo.class, UserFolderListsData.class, UserPlaylistResponse.PlayLists.class, InternetConnectionModel.class}, version = 3, exportSchema = false)
            

            我更新了这个版本号,它解决了这个问题。 出现问题是因为我在 SongInfo 类中添加了一个属性并忘记更新版本号。

            希望对某人有所帮助。

            【讨论】:

              【解决方案13】:

              如果您将 Room 版本从旧版本升级到 1.0.0-alpha9,请访问以下文章。从旧版本迁移到 1.0.0-alpha9 版本的非常好的文章。

              https://medium.com/@manuelvicnt/android-room-upgrading-alpha-versions-needs-a-migration-with-kotlin-or-nonnull-7a2d140f05b9

              In Room New Version 1.0.0-alpha9 Room 添加了对 NOT NULL 约束的支持。

              这将改变 Room 生成的架构。因为它改变了模式,它也改变了 DB 的 identityHash,Room 使用它来唯一地标识每个 DB 版本。因此,我们需要迁移

              【讨论】:

                【解决方案14】:

                在我的情况下,ContentProvider 和房间数据库一起工作,所以首先使用扩展 SqlLiteOpenHelper 类的数据库类删除整个应用程序中 ContentProvider 的所有回调

                【讨论】:

                  【解决方案15】:
                  @Database(entities = {Tablename1.class, Tablename2.class}, version = 3, exportSchema = false)
                  

                  更改 RoomDatabase 类中的版本号。增加版本号。

                  【讨论】:

                    【解决方案16】:

                    如果增加架构版本对您不起作用,请提供数据库迁移。为此,您需要在数据库构建器中声明迁移:

                    Room.databaseBuilder(context, RepoDatabase.class, DB_NAME)
                      .addMigrations(FROM_1_TO_2)
                    .build();
                    
                    static final Migration FROM_1_TO_2 = new Migration(1, 2) {
                    @Override
                    public void migrate(final SupportSQLiteDatabase database) {
                        database.execSQL("ALTER TABLE Repo 
                                         ADD COLUMN createdAt TEXT");
                        }
                    };
                    

                    【讨论】:

                    • 是的,这是正确的方式
                    【解决方案17】:

                    我刚刚在 espresso 测试中遇到了类似的问题,唯一解决它的是清除数据并卸载 androidx 测试 apk,例如:

                    adb uninstall androidx.test.orchestrator
                    adb uninstall androidx.test.services
                    

                    【讨论】:

                      【解决方案18】:

                      在我的例子中,我正在更新一个数据库,我将与我的应用程序一起预打包。这里的建议都没有奏效。但我终于发现我可以在数据库程序中打开 .db 文件(我使用“DB Browser for SQLite”),并手动将“用户版本”从 2 更改回 1。之后,它完美运行。

                      我猜您所做的任何更新都会更改此用户版本,这就是我不断收到此错误的原因。

                      【讨论】:

                      • 你能帮我做同样的事情吗?我无法在 DB Browser for SQLite 中找到版本
                      • 它位于“编辑编译指示”选项卡下。它被称为“用户版本”。
                      • 是的。我得到了它。感谢加文的帮助 :)
                      【解决方案19】:

                      快速解决方案

                      转到 AddDatabase 类并增加您的数据库版本

                      import androidx.room.Database
                      import androidx.room.RoomDatabase
                      import androidx.room.migration.Migration
                      import androidx.sqlite.db.SupportSQLiteDatabase
                      
                      @Database(entities = arrayOf(Product::class, SatisNok::class), version = 6)
                      abstract class AppDatabase : RoomDatabase() {
                          abstract fun productDao(): ProductDao
                          abstract fun satisDao(): SatisNokDao
                      }
                      

                      转到活动或您拨打db的地方

                      添加迁移的方法,这里我把版本从5改成了6

                        val MIGRATION_1_2: Migration = object : Migration(5,6) {
                                  override fun migrate(database: SupportSQLiteDatabase) {
                                      // Since we didn't alter the table, there's nothing else to do here.
                                  }
                              }
                      

                      现在将迁移添加添加到您的数据库 builder.addMigrations(MIGRATION_1_2)

                       val db = Room.databaseBuilder(
                                      applicationContext,
                                      AppDatabase::class.java, "supervisor"
                                  ).fallbackToDestructiveMigration()
                                      .allowMainThreadQueries()
                                      .addMigrations(MIGRATION_1_2)
                                      .build()
                      

                      有关更多详细信息,您可能希望查看here 它日益复杂,他们应该提供更简单的解决方案。

                      操作后您可以在 //.addMigrations(MIGRATION_1_2) 行注释并保留下次使用

                      【讨论】:

                        【解决方案20】:

                        我在 Codelabs 的培训计划中遇到了同样的错误。 在一次培训课程中,我创建了一个项目,它成功地运行了所有数据库操作。 在下一个会话中,我正在使用不同的存储库,但它是前一个项目的扩展,从扩展应用程序的第一个构建开始,我只得到了错误。

                        也许 Studio 在房间数据库中保留了身份验证技术 新版本缺少这一点。

                        【讨论】:

                          猜你喜欢
                          • 2017-11-16
                          • 2021-08-07
                          • 2020-09-13
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2021-07-15
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多