• Android-Room使用和迁移


    Room
    1. SQL基础上的一个抽象层
    使用
    1. 引入依赖
    def room_version = "2.4.3"
    implementation "androidx.room:room-runtime:$room_version"
    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$room_version"
    implementation("androidx.room:room-ktx:$room_version")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 定义数据库表
      使用@Entity注解
    @Entity(tableName = "User")
    class User {
    
        @PrimaryKey
        var id: Int = 0
    
        @ColumnInfo(name = "name")
        var name: String = ""
    
        @ColumnInfo(name = "address", defaultValue = "")
        var address: String = ""
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 定义数据表操作接口
      使用@Dao注解
    @Dao
    interface UserDao {
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        suspend fun insert(user: User)
    
        @Query("select * from user")
        fun getAll() : Flow<List<User>>
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 定义数据库接口
      使用@Database注解
    @Database(
        // entities可以维护多个class,代表多张数据库表
        entities = [User::class],
        version = 1,
    )
    abstract class UserDataBase : RoomDatabase() {
    	// 返回数据库访问接口
        abstract fun userDao(): UserDao
    
        companion object {
            private var userDataBase: UserDataBase? = null
    
            fun get(context: Context): UserDataBase {
                return userDataBase ?: synchronized(this) {
                    // lcj为数据库名
                    Room.databaseBuilder(context, UserDataBase::class.java, "lcj")
                        .build()
                        .also {
                            userDataBase = it
                        }
                }
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    1. 使用
    class UserViewModel(app:Application) : AndroidViewModel(app) {
    
        suspend fun insert(id: Int, name: String, address: String) {
            val user = User()
            user.id = id
            user.name = name
            user.address = address
            UserDataBase.get(getApplication()).userDao().insert(user)
        }
    
        fun getAll(): Flow<List<User>> {
            return UserDataBase.get(getApplication()).userDao().getAll().catch {
            }.flowOn(Dispatchers.IO)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    迁移
    自动迁移

    使用自动迁移,需要提供schema.location配置且@DataBase中的exportSchema必须设置为TRUE(默认为TRUE)

    1. build.gradle中进行如下配置,用于生成每个版本的数据库记录,Room用来跟踪数据库的变更
        defaultConfig {
            kapt {
                arguments {
                    arg("room.schemaLocation", "$projectDir/schemas")
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 新增列address
    @Entity(tableName = "User")
    class User {
    
        @PrimaryKey
        var id: Int = 0
    
        @ColumnInfo(name = "name")
        var name: String = ""
    
        // 版本2新增字段
        @ColumnInfo(name = "address", defaultValue = "")
        var address: String = ""
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 在Database注解中version升级到对应版本,且autoMigrations添加from to
    @Database(
        // entities可以维护多个class,代表多张数据库表
        entities = [User::class],
        // 修改版本号
        version = 2,
        // 新增自动迁移
        autoMigrations = [
            AutoMigration(from = 1, to = 2)
        ]
    )
    abstract class UserDataBase : RoomDatabase() {
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 生成的跟踪文件如下
      在这里插入图片描述

    注意:上面步骤,完成数据库中添加一列的升级。每当数据库版本再次改变时,您只需更新 autoMigrations 列表,添加一个新的AutoMigration即可。上述数据库表中新增了address列,对于自动迁移,Room自动会检测中这种变更,不需要开发者做其他操作。
    但是,有些自动迁移操作,Room无法检测出变化,需要开发者添加额外的spec,如,修改表名、列名、删除表、删除列,需要添加如下代码
    @DeleteTable(tableName)
    @RenameTable(fromTableName, toTableName)
    @DeleteColumn(tableName, columnName)
    @RenameColumn(tableName, fromColumnName, toColumnName)
    下面代码是从版本2升级到版本3,用于修改列名,此处在AutoMigration中添加了spec

    @Database(
        // entities可以维护多个class,代表多张数据库表
        entities = [User::class],
        version = 3,
        autoMigrations = [
            AutoMigration(from = 1, to = 2),
            AutoMigration(from = 2, to = 3, spec = UserDataBase.Migration2to3::class)
        ]
    )
    abstract class UserDataBase : RoomDatabase() {
    
        abstract fun userDao(): UserDao
    
        @RenameColumn(tableName = "User", fromColumnName = "address", toColumnName = "addressAt")
        class Migration2to3 : AutoMigrationSpec
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    手动迁移

    针对手动,Room 提供了 Migration 类。每当您要更改复杂的数据库时,您就得使用这个类。如:将数据库中的一个表拆分成两个不同的表,Room 无法检测到拆分的执行过程,也不能自动检测到需要移动的数据。因此这个时候,您需要实现一个 Migration 类,并通过 addMigrations() 的方法将其添加至 databaseBuilder() 中。

    companion object {
            private var userDataBase: UserDataBase? = null
    
            // 手动迁移
            private val migration = object : Migration(2, 3) {
                override fun migrate(database: SupportSQLiteDatabase) {
                    // 在这里进行手动迁移操作
    
                }
            }
    
            fun get(context: Context): UserDataBase {
                return userDataBase ?: synchronized(this) {
                    // lcj为数据库名
                    Room.databaseBuilder(context, UserDataBase::class.java, "lcj")
                        // 使用addMigrations添加自动迁移
                        .addMigrations(migration).build()
                        .also {
                            userDataBase = it
                        }
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    Paxos Made Simple
    文档管理使中型公司受益的 5 个方面
    java中@Qualifier注解的作用?
    java计算机毕业设计ssm+vue微空间私人定向共享系统
    Perl时间处理函数用法介绍
    浅析目标检测入门算法:YOLOv1,SSD,YOLOv2,YOLOv3,CenterNet,EfficientDet,YOLOv4
    如何使用 Tokenview NFT API进行 NFT 钱包的开发?
    【一种使用浏览器读取本地excel、josn等数据文件的方法】Python+JavaScript+HTML实现
    MAC 安装miniconda
    理解Spring Bean的创建过程和生命周期
  • 原文地址:https://blog.csdn.net/reuxfhc/article/details/127817797