一,修改Entity类,升级database的version,添加Migration对象用于升级
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("alter table MptModel add column isInternal INTEGER not null default 0");
database.execSQL("alter table MptModel add column internalScopes TEXT");
database.execSQL("delete from MptModel");
}
};
ScopeAuthorizeDatabase database = Room
.databaseBuilder(ContextUtils.getApplicationContext(),
ScopeAuthorizeDatabase.class, dbPath)
.addMigrations(MIGRATION_1_2)
.build();
二,为确保迁移成功,必须要做单元测试
根据本人亲身体验,强烈建议编写单元测试
单元测试可以尽可能多地测试各种场景,而且及时反馈,不仅降低出bug的可能,还提升了开发效率。
1,导出架构,添加以下配置,在编译时room会导出数据库架构信息到json文件;
将架构信息位置添加为资源文件夹
// module的build.gradle
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
}
dependencies {
androidTestImplementation "androidx.room:room-testing:2.2.1"
}
2,编写单元测试
首先创建一个helper类
测试时先创建低版本的数据库,插入数据,关闭数据库。然后执行迁移命令,检查数据库数据是否正常
public class ScopeAuthorizeDatabaseTest {
private static final String TEST_DB = "migration-scope-authorize-db-test";
@Rule
public MigrationTestHelper helper;
public ScopeAuthorizeDatabaseTest() {
helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
ScopeAuthorizeDatabase.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(
"insert into MptModel (miniAppId,miniAppMpt,openId) values ('ks001','hello','world')");
Cursor query1 = db.query("select * from MptModel");
query1.moveToFirst();
assertEquals(1, query1.getCount());
assertEquals(3, query1.getColumnCount());
// 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.
Cursor query2 = db.query("select * from MptModel");
query2.moveToFirst();
assertEquals(0, query2.getCount());// 升级策略是丢弃旧数据
assertEquals(5, query2.getColumnCount());
// 插入新数据
db.execSQL(
"insert into MptModel (miniAppId,miniAppMpt,openId) values ('ks001','hello','world')");
Cursor query3 = db.query("select * from MptModel");
assertEquals(1, query3.getCount());
query3.moveToFirst();
// 验证column
String miniAppId = query3.getString(query3.getColumnIndex("miniAppId"));
String miniAppMpt = query3.getString(query3.getColumnIndex("miniAppMpt"));
String openId = query3.getString(query3.getColumnIndex("openId"));
int isInternal = query3.getInt(query3.getColumnIndex("isInternal"));
String internalScopes = query3.getString(query3.getColumnIndex("internalScopes"));
assertEquals("ks001", miniAppId);
assertEquals("hello", miniAppMpt);
assertEquals("world", openId);
assertEquals(0, isInternal);// 默认为false
assertNull(internalScopes);// 默认为null
}
}
三,兜底策略
有时候可能缺失了部分升级路径,这时会发生IllegalStateException,为防止这种情况,需要使用兜底策略。
ScopeAuthorizeDatabase database = Room
.databaseBuilder(ContextUtils.getApplicationContext(),
ScopeAuthorizeDatabase.class, dbPath)
.addMigrations(MIGRATION_1_2)
.fallbackToDestructiveMigration()
.build();