【问题标题】:Identity hash check failed when testing Room migrations测试 Room 迁移时身份哈希检查失败
【发布时间】:2018-07-10 00:11:24
【问题描述】:

我正在按照these instructions 编写测试。我的测试班有这个规则:

@Rule
public MigrationTestHelper testHelper = new MigrationTestHelper(
        InstrumentationRegistry.getInstrumentation(),
        AppDatabase.class.getCanonicalName(),
        new FrameworkSQLiteOpenHelperFactory()
);

我的测试如下:

@Test
public void testMigration9_10() throws IOException {
    // Create the database with version 9
    SupportSQLiteDatabase db = testHelper.createDatabase(TEST_DB_NAME, 9);

    // Insert before migration
    ContentValues values = new ContentValues();
    values.put("rowid", 1);
    ...
    db.insert("foo", SQLiteDatabase.CONFLICT_FAIL, values);

    // Check inserted data
    Cursor c = db.query("SELECT * FROM foo WHERE rowid = " + values.get("rowid"));
    Assert.assertTrue(c.moveToFirst());
    Assert.assertEquals(c.getString(c.getColumnIndex("rowid")), values.get("rowid"));

    // Migrate
    db = testHelper.runMigrationsAndValidate(TEST_DB_NAME, 10, true, DatabaseCreator.MIGRATION_9_10);
    ...
}

但这在最后一行失败了(之前的断言很顺利),说:

java.lang.IllegalStateException: Room 无法验证数据完整性。看起来您已更改架构但忘记更新版本号。您可以通过增加版本号来解决此问题。

这是错误的。我已经追踪到发生了什么:

  • 使用版本 9 身份哈希创建数据库
  • 插入数据
  • 检查数据
  • 致电runMigrationsAndValidate,其中:
    • 打开数据库
    • 对照版本 10 检查身份哈希,但失败

在检查身份哈希时,它会:

private void checkIdentity(SupportSQLiteDatabase db) {
    createMasterTableIfNotExists(db);
    String identityHash = "";
    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)) {
        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.");
    }
}

所以加载的identityHash 是从数据库加载的,它是版本9;而mIdentityHashrunMigrationsAndValidate直接加载的,版本参数为10。

所以当然失败了。

我想知道为什么它在进行迁移之前检查身份哈希。

这是迁移,即使我认为这与这里无关:

public static final Migration MIGRATION_9_10 = new Migration(9, 10) {
    @Override
    public void migrate(@NonNull SupportSQLiteDatabase database) {
        database.beginTransaction();
        database.execSQL("ALTER TABLE DeclarationEntity ADD latitude REAL NOT NULL DEFAULT 0.0");
        database.execSQL("ALTER TABLE DeclarationEntity ADD longitude REAL NOT NULL DEFAULT 0.0");
        database.endTransaction();
    }
};

我是不是做错了什么?

PS:这里是完整的堆栈跟踪,以防万一这很有趣:

at android.arch.persistence.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:119)
at android.arch.persistence.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:100)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:133)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:282)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:175)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
at android.arch.persistence.room.testing.MigrationTestHelper.openDatabase(MigrationTestHelper.java:203)
at android.arch.persistence.room.testing.MigrationTestHelper.runMigrationsAndValidate(MigrationTestHelper.java:193)

我正在使用(versions.arch 是 1.0.0):

implementation "android.arch.persistence.room:runtime:${versions.arch}"
annotationProcessor "android.arch.persistence.room:compiler:${versions.arch}"
androidTestImplementation "android.arch.persistence.room:testing:${versions.arch}"

【问题讨论】:

    标签: android testing android-room android-instrumentation


    【解决方案1】:

    哦,好吧。原来我很傻。

    public static final Migration MIGRATION_9_10 = new Migration(9, 10) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.beginTransaction();
            database.execSQL("ALTER TABLE DeclarationEntity ADD latitude REAL NOT NULL DEFAULT 0.0");
            database.execSQL("ALTER TABLE DeclarationEntity ADD longitude REAL NOT NULL DEFAULT 0.0");
            database.setTransactionSuccessful(); // <--- TA-DAAAH
            database.endTransaction();
        }
    };
    

    框架确实运行了升级,但回滚了。

    【讨论】:

    • 另外,这是没用的:框架在调用migrate()之前启动一个事务,所以这根本没用。
    猜你喜欢
    • 2011-03-31
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 2022-01-04
    • 2015-02-05
    • 1970-01-01
    • 2020-12-13
    相关资源
    最近更新 更多