欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jetpack Room数据库

程序员文章站 2024-03-17 13:47:34
...

Jetpack Room数据库

简介
Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。
处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的用例是缓存相关数据。这样,当设备无法访问网络时,用户仍可在离线状态下浏览相应内容。设备重新连接到网络后,用户发起的所有内容更改都会同步到服务器。
由于 Room 负责为您处理这些问题,因此我们强烈建议您使用 Room(而不是SQLite)。

Jetpack Room数据库

依赖(AndroidX环境下)
在kotlin中使用需要添加kapt插件,在app的build.gradle文件的最上方添加如下代码:

apply plugin: 'kotlin-kapt'

然后在app的build.gradle文件中添加如下代码:

dependencies {
    ......你的其他依赖
    
    def room_version = "2.2.5"
    implementation "androidx.room:room-runtime:$room_version"
    //kotlin下使用
    kapt "androidx.room:room-compiler:$room_version"
    //java下使用
    //annotationProcessor "androidx.room:room-compiler:$room_version"
    
    //可选-Kotlin扩展和协程对Room的支持
    implementation "androidx.room:room-ktx:$room_version"
    
    //可选-RxJava对Room的支持
    implementation "androidx.room:room-rxjava2:$room_version"
    
    //可选-Guava对Room的支持,包括Optional和ListenableFuture
    implementation "androidx.room:room-guava:$room_version"
    
    //可选-需要用到相关测试工具的话
    testImplementation "androidx.room:room-testing:$room_version"
}

注意:避免出现Schema export directory is not provided警告,还需添加:

defaultConfig {
    //指定room.schemaLocation生成的文件路径  处理Room 警告 Schema export Error
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
        }
    }
}

Entity 实体类

@Entity(tableName = "users",primaryKeys = ["user_name","user_age"])
data class User(
    @PrimaryKey(autoGenerate = true) val id: Long,
    @ColumnInfo(name = "user_name") val name: String,
    @ColumnInfo(name = "user_age") val age: Int,
    @ColumnInfo val onLine: Boolean,
    @Ignore val remark: String
)

@Entity:定义表名、复合主键、索引等

  • tableName:设置表名字。默认是类的名字。
  • indices:设置索引。
  • inheritSuperIndices:父类的索引是否会自动被当前类继承。
  • primaryKeys:设置联合主键。
  • foreignKeys:设置外键。
  • ignoredColumns : 被忽略的字段。

@PrimaryKey:定义主键,autoGenerate设置是否自增
@ColumnInfo:定义字段名,name设置表中字段名,不设置默认为属性名
@Ignore:定义属性不被创建在表中

Dao 数据访问类

@Dao
interface UserDao {
    //查询所有用户
    @Query("select * from users")
    fun getUsers(): List<User>

    //根据ID查询用户
    @Query("select * from users where id = :id")
    fun getUserById(id: Long): User

    //根据用户名模糊查询用户
    @Query("select * from users where user_name Like '%' || :name ||'%'")
    fun getUsersByName(name: String): List<User>

    //根据用户名和年龄查询用户
    @Query("select * from users where user_name =:name and user_age >:age")
    fun getUsersByNameAndAge(name: String, age: Int): List<User>

    //插入用户
    /*  
        onConflict:默认值是OnConflictStrategy.ABORT,表示当插入有冲突的时候的处理策略。
                    OnConflictStrategy封装了Room解决冲突的相关策略:
       1. OnConflictStrategy.REPLACE:冲突策略是取代旧数据同时继续事务。
       2. OnConflictStrategy.ROLLBACK:冲突策略是回滚事务。
       3. OnConflictStrategy.ABORT:冲突策略是终止事务。
       4. OnConflictStrategy.FAIL:冲突策略是事务失败。
       5. OnConflictStrategy.IGNORE:冲突策略是忽略冲突。
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun addUsers(users: List<User>)

    //更新用户
    @Update
    fun updateUsers(users: List<User>)

    //删除用户
    @Delete
    fun deleteUser(user: User)

    //根据条件删除用户
    @Query("delete from users where id = :id")
    fun deleteUserById(id: Long)

}

Database 单例数据库

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        private var instance: AppDatabase? = null
        fun getInstance(context: Context): AppDatabase {
            if (instance == null) {
                instance = Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "data.db"
                ).allowMainThreadQueries().build()
            }
            return instance as AppDatabase
        }
    }
}

entities:数据库相关的所有Entity实体类,他们会转化成数据库里面的表。
可以传多个。例如:entities = [User::class,User1::class]
version:数据库版本。

数据库升级
当我们更新数据库表结构或新增表数据的时候,我们需要保留现有的数据,这时,我们需要对数据库进行更新,Room 支持通过 Migration 类进行增量迁移,以满足此需求。
具体操作如下:

  • 更新数据库版本
  • 创建Migration
  • 添加Migration到数据库
@Database(entities = [User::class], version = 2)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        private var instance: AppDatabase? = null
        fun getInstance(context: Context): AppDatabase {
            if (instance == null) {
                instance = Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "data.db"
                ).allowMainThreadQueries()
                    .addMigrations(MIGRATION_1_2)
                    .build()
            }
            return instance as AppDatabase
        }

        //给User表添加一个mobile字段
        private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE User " + " ADD COLUMN mobile TEXT")
            }
        }
    }
}

基本使用

val users = listOf(
    User(1, "张三", 20, true, "123456", ""),
    User(2, "李四", 22, true, "123456", "")
)
//插入
AppDatabase.getInstance(this)
    .userDao()
    .addUsers(users)

//查询
AppDatabase.getInstance(this)
    .userDao()
    .getUsers()

val updateUsers = listOf(
    User(1, "张三1", 20, true, "123456", ""),
    User(2, "李四2", 22, true, "123456", "")
)
//更新
AppDatabase.getInstance(this)
    .userDao()
    .updateUsers(updateUsers)

//删除
AppDatabase.getInstance(this)
    .userDao()
    .deleteUser(User(1, "张三1", 20, true, "123456", ""))

遇到的一些问题

  • 编译警告 Incremental annotation processing requested

    原因
    这是 Kotlin 1.3.50 的 bug,自 1.3.31 起,kapt 支持增量注解处理
    解决方法

  • 版本降级

    使用 1.3.41 或以下版本

  • 禁用增量编译

    在项目根目录下的 gradle.properties 文件中,
    添加 kapt.incremental.apt=false

  • 编译警告 Schema export directory is not provided to the annotation
    processor so we cannot export…
    原因
    没有指定room.schemaLocation生成的文件路径
    解决办法

  • 给RoomDatabase设置exportSchema注解为false

@Database(entities = [User::class], version = 2, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
  • 指定room.schemaLocation生成的文件路径
defaultConfig {
    //指定room.schemaLocation生成的文件路径  处理Room 警告 Schema export Error
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
        }
    }
}