Android Room 数据库之数据库升级

本篇文章主要介绍数据库的自动迁移和手动迁移,属于数据库升级的简单入门,不涉及复杂的数据迁移;

一、自动迁移

自动迁移即表示不用写迁移相关代码,Room通过比对新旧表不同实现自动迁移;需要的配置如下:

1. app/library gradle 配置

gradle配置主要是添加room插件,用于生成新旧表比对所需的json

gradle.kts 复制代码
plugins {
    ...
    // androidx-room = { id = "androidx.room", version = "2.6.1" }
    alias(libs.plugins.androidx.room)
}

android {
    ...
    room {
        //指定json文件要生成的目录,如:app/schemas/数据库类对应的包名
        schemaDirectory("$projectDir/schemas")
    }
}

解释一下schemaDirectory("$projectDir/schemas"):

  • projectDir就是模块的名称,比如是app模块则$projectDir/schemas等于app/schemas
  • 如果数据库类MyDatabase的报名是com.android.roomdemo.database.MyDatabase,那么生成的目录结构就是:app/schemas/com.android.roomdemo.database.MyDatabase/1.json,这里的1.json对应数据库的版本号version = 1

2. 数据库类配置

要支持自动迁移,必须设置exportSchema = true

kotlin 复制代码
@Database(entities = [Animal::class], version = 1, exportSchema = true)
abstract class MyDatabase : RoomDatabase() {
    abstract fun animalDao(): AnimalDao
}
新增表字段的情况

如下面这张表需要新增val belong: String字段

kotlin 复制代码
@Entity
data class Animal(val name: String, val age: Int, val sex: Int) {
    @PrimaryKey(autoGenerate = true) var id: Long = 0
}

Animal类改为

kotlin 复制代码
@Entity
data class Animal(val name: String, val age: Int, val sex: Int,
    @ColumnInfo(defaultValue = "")
    val belong: String,
) {
    @PrimaryKey(autoGenerate = true) var id: Long = 0
}

由于新增的belong是非null字符串,需要给默认值defaultValue = ""; MyDatabase修改如下,version+1,新增autoMigrations :

kotlin 复制代码
@Database(entities = [Animal::class], version = 2, exportSchema = true, 
    autoMigrations = [AutoMigration(from = 1, to = 2)]
)
abstract class MyDatabase : RoomDatabase() {
    abstract fun animalDao(): AnimalDao
}

新增字段最简单,只需加autoMigrations = [AutoMigration(from = 1, to = 2)],该字段是个数据,如果是2升级3,再加一个AutoMigration(from = 2, to = 3)即可;

删除表字段的情况

如果涉及的是删除表字段@DeleteColumn、修改表字段名@RenameColumn、删除表@DeleteTable、修改表名@RenameTable,则需要用到AutoMigrationSpec;它们的使用方法都类似,这里以删除表字段为例, 如果要删除Animal表中的sex字段,首先需要创建类实现AutoMigrationSpec接口:

kotlin 复制代码
@DeleteColumn.Entries(
    DeleteColumn(tableName = "Animal", columnName = "sex")
)
class DeleteAutoMigrationSpec : AutoMigrationSpec {
}

然后在MyDatabase里设置spec = DeleteAutoMigrationSpec::class:

kotlin 复制代码
@Database(
    entities = [Animal::class],
    version = 3, exportSchema = true, 
    autoMigrations = [
        AutoMigration(from = 1, to = 2),
        AutoMigration(
            from = 2,
            to = 3,
            spec = DeleteAutoMigrationSpec::class
        )
    ]
)
abstract class MyDatabase : RoomDatabase() {
    abstract fun animalDao(): AnimalDao
}

注意记得删除Animal类里的sex字段;到此,自动迁移适用于简单的数据修改。

手动数据迁移

手动数据迁移即通过自己写sql语句实现数据库升级,上面的MyDatabase类其实少了创建MyDatabase对象的方法,完整代码应该是这样:

kotlin 复制代码
@Database(
    entities = [Animal::class],
    version = 3, exportSchema = true, 
    autoMigrations = [
        AutoMigration(from = 1, to = 2),
        AutoMigration(
            from = 2,
            to = 3,
            spec = DeleteAutoMigrationSpec::class
        )
    ]
)
abstract class MyDatabase : RoomDatabase() {
    abstract fun animalDao(): AnimalDao
    
    companion object {

        @Volatile
        private var instance: MyDatabase? = null

        fun getInstance(context: Context): MyDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }
        
        private fun buildDatabase(context: Context): MyDatabase {
            // 创建数据库对象
            return Room.databaseBuilder(context, MyDatabase::class.java, "my-db")
                .build()
        }
    }
}

关注创建数据库对象方法:

kotlin 复制代码
Room.databaseBuilder(context, MyDatabase::class.java, "my-db").build()

手动迁移只要在build方法前加上.addMigrations(migration)即可,如现在要在Animal表里加val isGirl: Boolean字段,首先在Animal里加上该字段:

kotlin 复制代码
@Entity
data class Animal(val name: String, val age: Int, val isGirl: Boolean) {
    @PrimaryKey(autoGenerate = true) var id: Long = 0
}

然后创建Migration对象:

kotlin 复制代码
val migration_3_4 = object : Migration(3, 4) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE Wong ADD COLUMN isGirl INTEGER NOT NULL DEFAULT 0")
    }
}

addMigrations:

kotlin 复制代码
Room.databaseBuilder(context, MyDatabase::class.java, "my-db")
.addMigrations(migration_3_4)
.build()

完!

相关推荐
Decay__21 小时前
05_MySQL 常用 SQL 大全 —— 诊断、管理、优化辅助 SQL 与三大系统库速查
运维·数据库·sql·mysql·架构
小徐不徐说1 天前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
论文复现现场1 天前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
我是唐青枫1 天前
Kotlin Delegation 委托详解
开发语言·kotlin
Decay__1 天前
04_MySQL DBA 日常运维手册 —— 会话管理、锁与阻塞、事务监控、慢查询与日志巡检
运维·数据库·sql·mysql·架构
心梦缘-雪雁1 天前
SQL Server 查询数据存在哪个表里
数据库
lusklusklusk1 天前
Python 巡检脚本:进程运行状态、数据库写入时效检查及邮件通知与告警
数据库·python·oracle
GeW1 天前
产业新优势基础软件的人才底盘,从Linux与数据库开始
linux·数据库
SelectDB1 天前
Doris Arrow Flight SQL 高速读取协议实战:与 Snowflake 客户端取数链路对照
大数据·数据库·数据分析
曼岛_1 天前
[图解密码学]第4章 古典密码
java·数据库·密码学