这是我参与 8 月更文挑战的第 14 天,活动详情查看: 8月更文挑战
背景
在项目中不可避免的使用数据库, 而三方框架又是五花八门, 在这中我就选择了google Jetpack组件中的Room
上篇文章 简单介绍了一下room@Query
注解使用. 前几篇的文章基本把room的基本功能介绍完了, 但是由于需求的迭代升级, 有时第一版的数据库结构不能满足当前需求, 更改数据库字段就是涉及到数据库升级了
Migration
针对数据库升级,room提供了Migration
类和addMigrations
方法来支持,Migration
类源码如下:
public abstract class Migration {
public final int startVersion;
public final int endVersion;
public Migration(int startVersion, int endVersion) {
this.startVersion = startVersion;
this.endVersion = endVersion;
}
public abstract void migrate(@NonNull SupportSQLiteDatabase database);
}
从源码上看, Migration
只提供了一个构造方法, 从注释上看, Migration
提供新版本和旧版本直接的迁移, 构造方法需要传两个参数, 开始版本和结束版本
/**
* Creates a new migration between {@code startVersion} and {@code endVersion}.
*
* @param startVersion The start version of the database.
* @param endVersion The end version of the database after this migration is applied.
*/
实现
这里我采用的是内部类的方式, 如果为了方便查看已经代码格式问题, 可以去继承Migration
并实现migrate
方法,以从版本1升级到版本2为例
升级版本在
AppDatabase
的@Database
注解中更改version
版本
private static final Migration MIGRATION_1_2 = new Migration(1, 2)
{
@Override
public void migrate(@NonNull SupportSQLiteDatabase database)
{
//执行升级相关操作
}
};
以此类推,版本2升级到版本3如下
private static final Migration MIGRATION_2_3 = new Migration(2, 3)
{
@Override
public void migrate(@NonNull SupportSQLiteDatabase database)
{
//执行升级相关操作
}
};
在buildDB
时通过addMigrations()
方法添加升级逻辑,如下
addMigrations
方法接收的是一个可变参数, 如果需要添加多个升级逻辑,参数之间用,
隔开,.addMigrations(MIGRATION_1_2,MIGRATION_2_3,MIGRATION_3_4,....)
private static AppDatabase buildDB(Context context) {
return Room.databaseBuilder(context, AppDatabase.class, DATABASE_NAME)
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
}
异常
每升级一次版本,就需要添加一个Migration
逻辑, 如果忘记添加就会抛IllegalStateException异常,这是因为在数据库升级时未找到对应的Migration
逻辑, 从而导致数据库升级失败, 应用发生Crash. 为了防止这种情况发生, 我们可以通过fallbackToDestructiveMigration()
方法来避免,此方法可以在数据库升级异常时重新创建数据表,来避免升级失败导致应用发生Crash,但是由于重新创建数据库,就是导致数据丢失,看需求是什么样,再决定要不要添加此方法
private static AppDatabase buildDB(Context context) {
return Room.databaseBuilder(context, AppDatabase.class, DATABASE_NAME)
.fallbackToDestructiveMigration()
.addMigrations(MIGRATION_1_2)
.allowMainThreadQueries()
.build();
}