《Kotlin 系列》之Room 数据库+协程操作集(kotlin+room)
一、Room 是Jetpack 组件库中存储组件之一,是在SQLite 的一个抽象层,使用Room 可以有以下好处
- 针对 SQL 查询的编译时验证。
- 可最大限度减少重复和容易出错的样板代码的方便注解。
二、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:
转载自:https://juejin.cn/post/7218743537495998524