房间无法验证数据完整性

Room cannot verify the data integrity

我在 运行 使用 Room 数据库编程时遇到此错误

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 中从哪里进行更新?

如日志所示非常简单

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

只需转到您的数据库版本 class 并通过将当前版本增加 1 来升级您的数据库版本。

For Example : Find @Database annotation in your project like below

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

Here version = 1, is database version, you have to just increase it by one, That's it.

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

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

@Database(entities = {YourEntity.class}, version = 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-alpha9,请访问以下文章。从旧版本迁移到 1.0.0-alpha9 版本的非常好的文章。

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

In Room 新版本 1.0.0-alpha9 Room 添加了对 NOT NULL 约束的支持。

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

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

假设您的 DATABASE_VERSION 最初是 3,然后您决定将数据库版本从 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.
//        }
//    };
}

你可以这样实现

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

保持 DATABASE_VERSION 不变是个好习惯。

在我的例子中,ContentProvider 和房间数据库一起工作,所以首先删除整个应用程序中 ContentProvider 的所有回调,数据库 class 扩展了 SqlLiteOpenHelper Class

在我的例子中,我在迁移中使用了一个事务,而 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() 
}

在我的例子中,我有一个 AppDatabase class。

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

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

希望对大家有所帮助。

这个问题主要出现在开发中。

如果您更改您的架构,即 rename/add/modify 您的 class 包含 table 实体,则您之前构建中退出数据库的完整性与新构建冲突。

clear the app data or install new build after uninstalling the previous build.

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

android:allowBackup="true" inside AndroidManifest.xml 防止应用程序卸载后数据被清除。

将此添加到您的清单中:

android:allowBackup="false"

并重新安装应用程序。

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

另一种解法:

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

如果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.");
    }
}

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

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

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

请勿在生产代码中使用此解决方案!
改用, or

在 android phone:

Uninstall the app or Clear app data

要删除应用数据: 转到设置 -> 应用 -> Select 你的应用 -> 存储 -> 清除数据

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

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

第二个卸载应用程序或清除应用程序数据

@Database(entities = {Tablename1.class, Tablename2.class}, version = 3, exportSchema = false)

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

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

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");
    }
};

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

Maybe Studio keeps authentication techniques with room database that's missing with the new build.

在我的例子中,我更新了一个数据库,我将把它预先打包到我的应用程序中。 None 这里的建议奏效了。但我终于想通了,我可以在数据库程序中打开 .db 文件(我使用 "DB Browser for SQLite"),然后手动将 "User version" 从 2 改回 1。之后,它运行完美。

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

为了解决 kot​​lin 中的问题:

第一个

@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

快速解决方案

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

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
}

转到 Activity 或您打电话给 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)行,留待下次使用