数据库升级
第二篇:Room与LiveData、ViewModel结合使用
Migration
随着业务的变化,数据库可能也需要做一些调整,比如增加一个新字段,在Room中如何实现?Android为我们提供了一个Migration
类对Room进行升级。
Migration有两个参数,startVersion
和endVersion
,一个表示当前版本,一个表示将要升级到的版本。
使用方法
- 创建Migration
private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
//在这里做升级操作,比如增加或者减少表中的字段
database.execSQL("ALTER TABLE emperor_table ADD COLUMN gender TEXT");
}
};
-
添加到构建数据库的实例中
.addMigrations(MIGRATION_1_2)//可以添加多个参数,以便从1->2,2->3,1->3
-
最新版本号指定
@Database(entities = {Emperor.class}, version = 2)
异常处理
为了防止升级过程中失败导致应用程序崩溃的情况,可以在创建数据库时加入fallbackToDestructiveMigration()
方法。该方法能在数据库升级异常时,重建数据库而不崩溃,但是表中的数据会丢失。
Schemas文件查看版本升级情况
-
如何查看Room升级情况
- 在没有Room组件之前,若想要验证数据库的修改是否符合预期,我们需要找到这个数据库文件,接着使用第三方工具查看,对其进行查看和验证;
- 如果我们想查看数据库历次版本升级情况,只能通过版本控制工具,根据代码修改情况进行推测。
-
Room如何解决这个问题
-
Room提供了一项功能,在每次数据库升级过程中,都会导出一个Schema文件,这是一个
json
格式的文件,包含数据库所有信息; -
Schema默认是导出的,只需要在
build.gradle
中指定导出位置即可,若不想导出在进行如下设置即可@Database(entities = {Emperor.class}, version = 2, exportSchema = true)
-
销毁与重建策略
在Sqlite
中修改表结构比较麻烦,面对此类需求最好的方式是通过Migration
采用销毁和重建策略
- 创建一张符合表结构要求的临时表,
- 将数据从旧表复制到临时表,
- 删除旧表,
- 临时表重命名回原来的表名
代码示例
private static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
//创建临时表
database.execSQL("CREATE TABLE tem_emperor (" + "id INTEGER PRIMARY KEY NOT NULL," +
"emperor_name TEXT," +
"age INTEGER," +
"gender TEXT)");
//将数据导入临时表
database.execSQL("INSERT INTO tem_emperor (id,emperor_name,age,gender) SELECT id,emperor_name,age,gender FROM emperor_table");
//删除原表
database.execSQL("DROP TABLE emperor_table");
//临时表改成原表的名字
database.execSQL("ALTER TABLE tem_emperor RENAME TO emperor_table");
}
};