一、Room 是Jetpack 组件库中存储组件之一,是在SQLite 的一个笼统层,运用Room 可以有以下好处

  • 针对 SQL 查询的编译时验证。
  • 可最大限度削减重复和简单犯错的样板代码的便利注解。

二、room 组成结构图和解析

《Kotlin 系列》之Room 数据库+协程操作集(kotlin+room)

三、Room 组成部分

  • 数据库类: 用于保存数据库并作为应用持久性数据底层衔接的主要拜访点。
  • 数据实体: 用于表示应用的数据库中的表。
  • 数据拜访目标 (DAO): 提供您的应用可用于查询、更新、刺进和删去数据库中的数据的办法。

四、kotlin 中运用room

1、导入room kt库,注意,运用 kapt是必要的!!

	    //room数据库
    api "androidx.room:room-runtime:2.4.2"
    kapt "androidx.room:room-compiler:2.4.2" // Kotlin 运用 kapt
    api "androidx.room:room-ktx:2.4.2"//Coroutines support for Room 协程操作库

2、数据实体类编码

package com.kt.ktmvvm.jetpack.room.db
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "User")
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "name") val name: String?,
    @ColumnInfo(name = "sex") val sex: String?,
)
data class UserName(val uid: Int, val name: String?)

3、数据拜访目标 (DAO)


@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    suspend fun getAll(): List<User>?
    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    suspend fun loadAllByIds(userIds: IntArray): List<User>?
    @Query("SELECT * FROM user WHERE name LIKE :name")
    suspend fun findByName(name: String): User?
    @Query("SELECT *FROM user WHERE uid LIKE:userId")
    suspend fun findById(userId: Int): User?
    @Update(entity = User::class)
    suspend fun updateSingleName(vararg name: UserName?)
    @Update
    suspend fun updateUser(vararg user: User)
    @Insert
    fun insertAll(vararg users: User)
    @Delete
    fun delete(user: User)
}

简直所有的办法都运用了suspend 挂起,便利在协程中运用,还无需手动切换线程。 以上的Dao 包含了 增(insert)\删(Delete)\改(Update)\查(Query),其中Update 可以更新一整行,也可以对某个字段独自更新。

4、数据库类

数据库类可以设计成一个单例模式,如下:

@Database(entities = [User::class], version = 2)
abstract class UserDataBase : RoomDatabase() {
    abstract fun userDao(): UserDao
    companion object {
        private var instance: UserDataBase? = null
        private val TAG: String? = UserDataBase::class.simpleName
        fun get(context: Context): UserDataBase {
            if (instance == null) {
                instance = Room.databaseBuilder(context, UserDataBase::class.java, "user_.db")
                    .fallbackToDestructiveMigration()
                    //是否答应在主线程进行查询
                    .allowMainThreadQueries()
                    .fallbackToDestructiveMigration()
                    .addCallback(object : Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            Log.e(TAG, "onCreate db_name is=" + db.path)
                        }
                    })
                    .build()
            }
            return instance!!
        }
    }
}

至此,三个Room组成部分对应的编码现已结束,下面看看怎样运用。

五、协程运用标准(viewModelScope)

  • 增:
  viewModelScope.launch {
            //随机创立一个random
            val random = (1..10).random()
            //先查询再刺进
            val hotDog = UserDataBase.get(getApplication()).userDao().findById(random)
            hotDog?.let {
                Log.d(TAG, "现已有一条相同的数据啦")
            } ?: randomInsert(random)
            //先查询,假如没这条数据 就刺进,有的话打印数据
        }
  • 删:

    /**
     * 删去数据
     */
    fun deleteAllData() {
        viewModelScope.launch {
            //随机取一条数据
            val random = (1..10).random()
            //查询数据库是否有此条数据
            val user = UserDataBase.get(getApplication()).userDao().findById(random)
            user?.let {
                UserDataBase.get(getApplication()).userDao().delete(user)
                Log.d(TAG, "删去某条数据成功")
            } ?: randomInsert(random)
        }
    }
  • 改:
    /**
     * 随机更新某条User数据
     */
    fun updateRandomData() {
        //先查询
        val random = (1..10).random()
        viewModelScope.launch {
            val user = UserDataBase.get(getApplication()).userDao().findById(random)
            user?.let {
                //假如不为空,则更新
                UserDataBase.get(getApplication()).userDao()
                    .updateUser(User(random, "我是更新整个user后的数据", "男"))
                Log.d(TAG, "更新整个user数据成功")
            } ?: randomInsert(random)
        }
    }
    /**
     * 随机独自更新某个字段
     */
    fun updateSingleData() {
        //先查询
        val random = (1..10).random()
        viewModelScope.launch {
            val user = UserDataBase.get(getApplication()).userDao().findById(random)
            user?.let {
                UserDataBase.get(getApplication()).userDao()
                    .updateSingleName(UserName(random, "我是独自更新后的数据"))
                Log.d(TAG, "更新独自数据成功")
            } ?: randomInsert(random)
        }
    }
    * 随机刺进某条数据,便利测试
     */
    private fun randomInsert(random: Int) {
        val mD = User(random, "热狗先生$random", "女")
        UserDataBase.get(getApplication()).userDao().insertAll(mD)
        Log.d(TAG, "刺进数据成功")
    }

以上便是基本的增、删、改、查基本操作编码。下面看看数据晋级相关语法

六、数据库晋级常用语法

数据库晋级会涉及到database 中的version ,在app 版本迭代中,当呈现添加字段 或者改名,都需要做数据库晋级, 在数据库晋级中,有可能语法犯错,为了躲避报错,可以装备当晋级失利时,回滚到上一个版本。

    instance = Room.databaseBuilder(context, UserDataBase::class.java, "user_.db")
                    .fallbackToDestructiveMigration()
                    //是否答应在主线程进行查询
                    .allowMainThreadQueries()
                    .fallbackToDestructiveMigration()// 设置晋级战略,失利会回滚到上一个版本
                   .addMigrations(ADD_FIELD_MIGRATION_1_2)
                    .addCallback(object : Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            Log.e(TAG, "onCreate db_name is=" + db.path)
                        }
                    })
                    .build()

1、添加字段晋级语法


        /**
         * 添加字段晋级(添加一个String 类型 的字段sex)
         */
        private val ADD_FIELD_MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE User ADD COLUMN sex Text")
            }
        }

以上便是kotlin 运用room 最基础的语法了。后续有杂乱运用,会一向更新。 代码已上传gitHub:

github.com/ljlstudio/K…