Android Architecture Component Room持久化数据库(五)迁移Room数据库

版权声明:本文为博主原创文章,欢迎大家转载!

但是转载请标明出处: https://blog.csdn.net/t000818/article/details/84303795 ,本文出自:【唐宏宇的博客】


在应用程序中添加和更改功能时,需要修改数据库实体类以映射这些更改。当用户更新到最新版本的应用程序时,您不希望它们丢失所有现有数据,尤其是在您无法从远程服务器恢复数据时。

Room persistence library 库可以通过编写Migration类以保留用户数据。每个Migration类都指定一个startVersion和endVersion。在运行时,Room会运行每个Migration类的migrate()方法,使用正确的顺序将数据库迁移到更高版本。

Kotlin写法:

val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, `name` TEXT, " +
                "PRIMARY KEY(`id`))")
    }
}

val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE Book ADD COLUMN pub_year INTEGER")
    }
}

Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()

Java写法:

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");
    }
};

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();


警告:要使迁移逻辑按预期运行,请使用完整查询,而不是引用表示查询的常量。

迁移过程完成后,Room会验证模型以确保正确进行迁移。如果Room发现问题,则会抛出包含不匹配信息的异常。

 

测试数据迁移

迁移并不是一件容易的事,但是如果没有正确编写它们可能会导致应用程序出现崩溃循环。为了保持应用程序的稳定性,您应该事先测试迁移。 Room提供测试Maven依赖库以协助此测试过程。但是,要使此依赖库生效,您需要导出数据库的模型。

 

导出模型

在编译时,Room会将数据库的模型信息导出到JSON文件中。要导出架构,请在build.gradle文件中设置room.schemaLocation解处理器属性,如以下代码段所示:

build.gradle

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation":
                             "$projectDir/schemas".toString()]
            }
        }
    }
}

测试包提供了MigrationTestHelper类,可以读取这些模型文件。它还实现了JUnit4 TestRule接口,因此它可以管理已创建的数据库。

以下代码段中显示了示例迁移测试:

Kotlin写法:

@RunWith(AndroidJUnit4::class)
class MigrationTest {
    private val TEST_DB = "migration-test"

    @Rule
    val helper: MigrationTestHelper = MigrationTestHelper(
            InstrumentationRegistry.getInstrumentation(),
            MigrationDb::class.java.canonicalName,
            FrameworkSQLiteOpenHelperFactory()
    )

    @Test
    @Throws(IOException::class)
    fun migrate1To2() {
        var db = helper.createDatabase(TEST_DB, 1).apply {
            // db has schema version 1. insert some data using SQL queries.
            // You cannot use DAO classes because they expect the latest schema.
            execSQL(...)

            // Prepare for the next version.
            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.
    }
}

Java写法:

@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.
    }
}

 

优雅地处理丢失的迁移路径

更新数据库的模型后,某些设备上的数据库仍可能使用较旧的模式版本。如果Room无法找到将该设备的数据库从旧版本升级到当前版本的迁移规则,则会发生IllegalStateException。

要防止应用程序在发生这种情况时崩溃,请在创建数据库时调用fallbackToDestructiveMigration()构建器方法:

Kotlin写法:

Room.databaseBuilder(applicationContext, MyDb::class.java, "database-name")
        .fallbackToDestructiveMigration()
        .build()

Java写法:

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .fallbackToDestructiveMigration()
        .build();

通过在应用程序的数据库构建逻辑中加入此子句,可以告知到Room在缺少数据库模型的版本之间迁移路径的情况下,破坏性地重新创建应用程序的数据库表。

警告:通过在应用程序的数据库构建器中配置此选项,Room会在缺少迁移路径时永久删除数据库表中的所有数据。
破坏性回退逻辑包括几个附加选项:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值