数据库Room之迁移数据库(译)

原文链接:https://developer.android.com/training/data-storage/room/migrating-db-versions?hl=zh-cn
随着应用中功能的调整和增加,一些Entity类就需要作出相应变化。当用户更新到最新的版本时,我们不希望丢失用户的全部数据,特别是那些不能从服务端恢复的数据。
Room可以通过实现Migration类来保留原先的数据。每个Migration类规定了startVersion和endVersion。在运行时,Room会执行每个Migration类的migrate()方法,在正确的执行顺序下使数据库更新到升级到最新版本。

重要提示:如果没有提供migration,那么Room会重建数据库,这将导致丢失数据库中所有的老数据。

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
                + "`name` TEXT, PRIMARY KEY(`id`))");
    }
};

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE Book "
                + " ADD COLUMN pub_year INTEGER");
    }
};

重要提示:为了让你的迁移操作正确进行,请使用完整的操作而不是通过已经存在的操作结果。

迁移操作结束后,Room会做检查以确认迁移正确的执行了。如果Room检测到错误就会抛异常。

测试迁移

迁移操作不是简单的修改,如果操作失败的话会导致应用一直崩溃。为了提高应用的稳定性,我们需要提前测试好。Room提供了相应的依赖来帮助我们测试。但是要使该依赖起作用,你需要导出数据库。

导出数据库

Room会在编辑阶段就导出数据库结构到一个JSON文件里。在导出前,你需要在build.gradle中配置编译时注解参数room.schemeLocation,示例代码如下:
build.gradle

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation":
                             "$projectDir/schemas".toString()]
            }
        }
    }
}

我需要保存数据库结构的历史记录,这样的话就能在后期测试数据库迁移问题。
为了测试迁移,需要添加依赖 android.arch.persistence.room:testing,然后指定保存数据的文件夹,示例代码如下:
build.gradle

android {
    ...
    sourceSets {
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }
}

测试包里提供了MigrationTestHelper类,它可以帮助我们读取数据库结构文件。同时它也实现了JUnit4的TestRule,所以它能控制已经创建的数据库。
示例代码如下:

@RunWith(AndroidJUnit4.class)
public class MigrationTest {
    private static final String TEST_DB = "migration-test";

    @Rule
    public MigrationTestHelper helper;

    public MigrationTest() {
        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                MigrationDb.class.getCanonicalName(),
                new FrameworkSQLiteOpenHelperFactory());
    }

    @Test
    public void migrate1To2() throws IOException {
        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);

        // db has schema version 1. insert some data using SQL queries.
        // You cannot use DAO classes because they expect the latest schema.
        db.execSQL(...);

        // Prepare for the next version.
        db.close();

        // Re-open the database with version 2 and provide
        // MIGRATION_1_2 as the migration process.
        db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2);

        // MigrationTestHelper automatically verifies the schema changes,
        // but you need to validate that the data was migrated properly.
    }
}

你可能感兴趣的:(数据库Room之迁移数据库(译))