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()

完!

相关推荐
IvorySQL12 小时前
PostgreSQL 日报|修复截断 zstd 备份检测(10 月 9 日)
数据库·postgresql
墨天梦12 小时前
B19_SunnyWeather到阅读客户端
android·kotlin
刘胡子大叔12 小时前
SQL 脚本的导入顺序
数据库·sql
代码什么用13 小时前
Spring对IoC的实现
数据库·spring
hz5678915 小时前
涉密视频会议设备配置指南:终端、音视频采集与配套设施选型
服务器·网络·数据库·安全·实时音视频·信息与通信·智能硬件
广州浮点FLOATLIC15 小时前
许可证服务器迁移后软件打不开:研发 IT 怎样定位连接问题
linux·服务器·数据库
程序员Sunday15 小时前
MySQL 为什么使用 B+ 树索引?把范围查询、回表和覆盖索引连起来
数据库·mysql
半杯咖啡半行码15 小时前
Qt开发实战:数据库、MV 模式、QProcess与串口通信全攻略
数据库·qt
小米里的大麦15 小时前
16 MySQL 事务
数据库·mysql
西柚小萌新15 小时前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库