Android Developers官方文档翻译:Room(四)

数据库升级

(原文直译应该是数据库迁移,但按我们正常术语一般表达为数据库升级、数据迁移,所以这里翻译为“升级”)
在App的功能有改动的时候,如果涉及到数据库中的实体类,你同时还要修改这些实体类的代码。当一个用户将你的App更新到最新的时候,你一定不希望他们丢失所有的数据,特别是那些你无法从远程服务器中恢复的数据。

Room提供Migration类,通过Migration类可以在这种情况中保留用户的数据。每一个Migration类都会标明一个startVersion和endVersion。在运行的时候,Room将会依次执行每一个Migration类的migrate()方法,从而保证数据库以一个正确的顺序升级到最新版本。

注意:如果你不提供必需的migrations类,Room将会重建数据库,这意味你会丢失数据库中的所有数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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");
}
};

注意:在数据库升级中请使用完整的sql语句书写,而不是引用表示查询的常量,这是为了保证数据升级逻辑的正常执行。

在数据库升级代码执行完后,Room会验证schema来确保迁移的正常执行情况。如果Room发现任何问题,将抛出包含有错误信息的异常。

测试升级后的数据库

写数据库升级的代码不是一件小事,因为一丁点错误都可能导致你的app循环崩溃。为了保证app的稳定性,你应该在打包前先进行测试。Room提供了Maven插件来帮助开发者完成数据库测试,但使用这个插件之前,你要先把你数据库的schema导出。

导出schemas

编译后,Room会将数据库的schema信息保存在一个JSON文件中。要导出这个schema,需要在build.gradle中配置room.schemaLocation相关信息,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
}

你应该在你的版本控制系统中保存好(归档好)记录数据库历史版本schema的JSON文件,这将对你后续升级版本的测试中起到必要的帮助,不然,你怎么创建旧的数据库来测试数据库升级。

另外,要测试数据库升级,需要增加android.arch.persistence.room:testing这个Maven插件到你的test依赖中,还要增加schema文件的路径作为一个asset路径,示例代码如下:

1
2
3
4
5
6
android {
...
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
}

测试包提供一个MigrationTestHelper,这个类可以读取schema文件的内容。同时它实现了JUnit4的TestRule接口,因此可以使用它来管理创建的数据库。

一个简单的数据库升级测试示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@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.
}
}

原文链接:https://developer.android.com/training/data-storage/room/migrating-db-versions

文章作者: Kevin Wu
文章链接: https://kevinwu.cn/p/c653ccbd/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 KevinWu.CN
支付宝打赏