Android Jetpack组件-Room 数据库升级

764 阅读2分钟

这是我参与 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();
}