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. 定义数据库表
    使用@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. 定义数据表操作接口
    使用@Dao注解
@Dao
interface UserDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(user: User)

    @Query("select * from user")
    fun getAll() : Flow<List<User>>

}
  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. 使用
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)
    }
}

迁移

自动迁移

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

  1. build.gradle中进行如下配置,用于生成每个版本的数据库记录,Room用来跟踪数据库的变更
    defaultConfig {
        kapt {
            arguments {
                arg("room.schemaLocation", "$projectDir/schemas")
            }
        }
    }
  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. 在Database注解中version升级到对应版本,且autoMigrations添加from to
@Database(
    // entities可以维护多个class,代表多张数据库表
    entities = [User::class],
    // 修改版本号
    version = 2,
    // 新增自动迁移
    autoMigrations = [
        AutoMigration(from = 1, to = 2)
    ]
)
abstract class UserDataBase : RoomDatabase() {
  1. 生成的跟踪文件如下
    Android-Room使用和迁移_第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
手动迁移

针对手动,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
                    }
            }
        }
    }

你可能感兴趣的:(Android,android)