Room数据库使用与踩坑(最新)
目录
- 一、介绍
- 二、引入
- 三、使用(增删改查)
- 数据实体
- 数据访问对象
- 数据库
- 3.1 增
- 3.2 删
- 3.3 改
- 3.4 查
- 四、更新数据库
- 4.1自动迁移
- 使用
- 4.2手动迁移
一、介绍
关于Room数据库的介绍可以看Android官方的(使用 Room 将数据保存到本地数据库 | Android 开发者 | Android Developers),这里主要介绍一些官方缺少的和一些踩坑。
二、引入
如需在应用中使用 Room,请将以下依赖项添加到应用的 build.gradle
文件:
注意:Room的版本号与kotlin的版本号需要对应
dependencies {implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.72"implementation 'androidx.core:core-ktx:1.3.2'def latest_version = "2.2.5"//roomimplementation "androidx.room:room-runtime:$latest_version"implementation "androidx.room:room-ktx:$latest_version"kapt "androidx.room:room-compiler:$latest_version"// optional - 支持Rxjava2与Roomimplementation "androidx.room:room-rxjava2:$latest_version"// optional - 支持协程与Roomimplementation("androidx.room:room-ktx:$latest_version")}
三、使用(增删改查)
使用前需要先准备数据实体,数据访问对象(DAO),数据库
数据实体
@Entity
class RunRecord {@PrimaryKey(autoGenerate = true)var id: Long? = null@ColumnInfo(name = "userId")var userId: String? = null@ColumnInfo(name = "pathLine")var pathLine: String? = null@ColumnInfo(name = "totalStep")var totalStep:Int? = 0
}
数据访问对象
注意:返回主键ID类型与数据实体中的主键类型对应。或者实体中的类型是Int,插入成功返回Long/Int,不能相反。
@Dao
interface RunDao {/**** 插入一条信息,id不用传,会自动增长.建议不传* @return Long 返回插入的主键id*/@Insertfun insert(info: RunRecord?): Long@Query("INSERT into RunRecord(userId,pathLine) values(:userId,:pathLine) ")fun insert(userId: String?, pathLine: String?): Long/*** @return Int 1 成功 0失败*/@Deletefun delete(info: RunRecord?): Int@Query("DELETE FROM RunRecord WHERE userId = :userId")fun delete(userId: String?): Int/*** @return Int 返回删除的条数*/@Query("DELETE FROM RunRecord")fun deleteAll(): Int/*** @return Int 1 成功 0失败*/@Updatefun update(vararg info: RunRecord?): Int@Query("UPDATE RunRecord SET pathLine =:info WHERE userId = :userId")fun updateRunInfo(userId: String, info: String): Int/*** 根据userId获取最后一条*/@Query("SELECT * FROM RunRecord WHERE userId LIKE :userId order by userId desc LIMIT 1")fun findLastByUserId(userId: String): RunRecord?/*** 查询全部数据*/@get:Query("SELECT * FROM RunRecord")val all: List<RunRecord?>?
}
数据库
@Database(entities = [ RunRecord::class], version = 1)
abstract class YzDatabase : RoomDatabase() {abstract fun runDao(): RunDao?companion object {private const val DB_NAME = "yzWill.db"@Volatileprivate var instance: YzDatabase? = nullfun getInstance(context: Context) =instance ?: synchronized(this) {instance ?: Room.databaseBuilder(context,YzDatabase::class.java, DB_NAME).build()}}
}
注意:Room的操作都需要在子线程执行,如果需要在主线程执行需要设置allowMainThreadQueries()方法
如下设置:
fun getInstance(context: Context) =instance ?: synchronized(this) {instance ?: Room.databaseBuilder(context,YzDatabase::class.java, DB_NAME).allowMainThreadQueries().build()}
3.1 增
插入一条数据,返回主键ID,初始也就是1
@Insert用法
val db = YzDatabase.getInstance(this).runDao()
Thread() {//插入一条数据,返回主键idval id = db?.insert(RunRecord().apply {pathLine = "插入一条信息"userId = "小小虫"})Log.e(tag, "id:$id")
}.start()
@Query("INSERT into RunRecord(userId,pathLine) values(:userId,:pathLine) ") 用法
val db = YzDatabase.getInstance(this).runDao()
Thread() {//插入一条数据pathLine = "插入一条信息1",userId = "小小虫1",返回主键idval id = db?.insert(pathLine = "插入一条信息1", userId = "小小虫1")Log.e(tag, "id:$id")
}.start()
3.2 删
删除一条信息,返回0或1。注意:这里删除必须传ID,也就是主键,因为 @Delete 注解只根据主键识别,后面的 @Update 也是如此
@Delete 用法
val db = YzDatabase.getInstance(this).runDao()
Thread() {//删除ID为1的数据,返回 0:删除失败 1:删除成功val success = db?.delete(RunRecord().apply {id = 1})Log.e(tag, "success:$success")
}.start()
@Query("DELETE FROM RunRecord WHERE userId = :userId") 用法
val db = YzDatabase.getInstance(this).runDao()
Thread() {//删除userId = "小小虫"的数据,返回删除的条数val count = db?.delete( userId = "小小虫")Log.e(tag, "count:$count")
}.start()
@Query("DELETE FROM RunRecord") 用法
val db = YzDatabase.getInstance(this).runDao()
//删除所有数据,返回删除的条数
Thread() {val count = db?.deleteAll()Log.e(tag, "count:$count")
}.start()
3.3 改
@Query("UPDATE RunRecord SET pathLine =:info WHERE userId = :userId")用法
val db = YzDatabase.getInstance(this).runDao()
//更新 userId = "小小虫" 的一数据,修改info = ="修改一条信息"
// 返回 0:更新失败 1:更新成功
Thread() {val success = db?.updateRunInfo(userId = "小小虫", info = "修改一条信息")Log.e(tag, "success:$success")
}.start()
@Update 用法也是根据主键ID查找对应数据修改
val db = YzDatabase.getInstance(this).runDao()
//更新 id = 1 的一条数据,,返回 0:更新失败 1:更新成功
Thread() {val success = db?.update(RunRecord().apply {id = 1pathLine = "修改一条信息"userId = "小小虫1"})Log.e(tag, "success:$success")
}.start()
3.4 查
@Query("SELECT * FROM RunRecord WHERE userId LIKE :userId order by userId desc LIMIT 1")
val db = YzDatabase.getInstance(this).runDao()
Thread() {//根据userId获取最后一条val info = db?.findLastByUserId(userId = "小小虫")Log.e(tag, "info:$info")
}.start()
@get:Query("SELECT * FROM RunRecord")
val db = YzDatabase.getInstance(this).runDao()
//查询所有数据,返回表所有数据
Thread() {val info = db?.allinfo?.forEach {Log.e(tag, "it:$it")}
}.start()
四、更新数据库
当我们需要在原有的数据库里添加表或者在原有的表里添加新的字段时,需要更新数据库才能使我们新加的内容得以应用。
4.1自动迁移
注意:Room 在 2.4.0-alpha01 及更高版本中支持自动迁移。如果您的应用使用的是较低版本的 Room,则必须手动定义迁移。
不建议使用这种方式,因为高版本的Room需要更新Kotlin 版本,Kotlin插件版本,Gradle版本等,而且还要升级Android Studio,我放弃了!!
关于这些具体的版本号查看这里:https://github.com/googlecodelabs/android-room-with-a-view/archive/kotlin.zip
使用
旧版本
@Database(entities = [ RunRecord::class], version = 1)
abstract class YzDatabase : RoomDatabase() {
新版本
@Database(entities = [ RunRecord::class], version = 2,autoMigrations = [AutoMigration (from = 1, to = 2)])
abstract class YzDatabase : RoomDatabase() {
4.2手动迁移
在RunRecord表中加一个userName字段和std字段
@ColumnInfo(name = "userName")
var userName: String? = null@ColumnInfo(name = "std")
var std: Int? = null
步骤:
1.将version+1
@Database(entities = [ RunRecord::class], version = 2)
2.创建Migration(int startVersion,int endVersion)类,startVersion原始版本号(例如1),endVersion升级后的版本号(例如2)
提示:由于SQLite好像不支持像数据库一样多个字段添加,所以只能分开添加
val MIGRATION_1_2: Migration = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {database.execSQL("ALTER TABLE RunRecord"+ " ADD COLUMN userName TEXT")database.execSQL("ALTER TABLE RunRecord"+ " ADD COLUMN std INTEGER")}}
3.将Mrgration添加到数据库构建中
fun getInstance(context: Context) =instance ?: synchronized(this) {instance ?: Room.databaseBuilder(context,YzDatabase::class.java, DB_NAME).addMigrations(MIGRATION_1_2).build()}
完整代码
@Database(entities = [ RunRecord::class], version = 2)
abstract class YzDatabase : RoomDatabase() {abstract fun runDao(): RunDao?companion object {private const val DB_NAME = "yzWill.db"val MIGRATION_1_2: Migration = object : Migration(1, 2) {override fun migrate(database: SupportSQLiteDatabase) {database.execSQL("ALTER TABLE RunRecord"+ " ADD COLUMN userName TEXT")database.execSQL("ALTER TABLE RunRecord"+ " ADD COLUMN std INTEGER")}}@Volatileprivate var instance: YzDatabase? = nullfun getInstance(context: Context) =instance ?: synchronized(this) {instance ?: Room.databaseBuilder(context,YzDatabase::class.java, DB_NAME).addMigrations(MIGRATION_1_2).build()}}
}
注意:每次更新的MIGRATION_1_2,MIGRATION_2_3等都要加到构建中去,不能只单单 addMigrations(MIGRATION_2_3),如果此时手机安装的数据库版本是2,那就没问题。如果是1,那么app会闪退
Room数据库使用与踩坑(最新)相关推荐
- 数据存储之SQLCipher数据库解密访问踩坑:net.sqlcipher.database.SQLiteException: file is not a databaseAndroid
数据存储之SQLCipher数据库解密访问踩坑: 需求是打开一个别处加密的db,前提是有密码,废话不多,都是干货. net.sqlcipher.database.SQLiteException: fi ...
- MySQL导入官方数据库world防踩坑完全操作
1.在MySQL官方网站下载官方数据集world,链接.下载zip格式文件然后解压即可,是一个名叫world.sql的文件 2.打开电脑中mysql安装目录下的my.ini文件,找到secure_fi ...
- boot数据加解密 spring_SpringBoot 集成 Jasypt 对数据库加密以及踩坑
前言 密码安全是非常重要的,因此我们在代码中往往需要对密码进行加密,以此保证密码的安全 加依赖 <!-- jasypt --> <dependency><groupId& ...
- 最新Ubuntu20.04安装指南(防踩坑版)
文章目录 最新Ubuntu20.04安装.配置指南(防踩坑版) 一.备份(!!!) (1)Windows系统镜像 (2)个人资料 (3)一些杂项 二.启动盘UEFI引导 1.启动盘制作 2.设置以U盘 ...
- centos 安装2个mysql_CentOs服务器下安装两个个MySql数据库踩坑日记
背景: 其实并非本意非要安装两个服务器,奈何不知道前面项目的数据库密码,并且数据库版本是8.x,另外还有项目在上面运行,前面的人把数据库装到了系统盘,留下了500G的数据盘没用,所以本着折腾的精神,就 ...
- C++踩坑之连接mysql数据库
C++踩坑之连接mysql数据库 实现的效果 https://www.cr173.com/soft/105990.html 下载connect C++ 安装软件 安装到D盘,安装32位即可 64位不要 ...
- Spark踩坑记——数据库(Hbase+Mysql)转
转自:http://www.cnblogs.com/xlturing/p/spark.html 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库 ...
- 把握数据库发展趋势 DBA应如何避免“踩坑”?
在DTCC 2019大会上,阿里云智能数据库产品事业部高级产品专家萧少聪做了题为<如何构建云时代DBA的知识体系>的演讲,进行云时代以后,IT行业各工种的职责都在发生变化,云数据库使得日常 ...
- v-for和v-if同时使用(案例分析:循环最新的前14条数据显示) - 踩坑篇
Vue官方文档:永远不要把 v-if 和 v-for 同时用在同一个元素上. 官方文档: 避免 v-if 和 v-for 用在一起 阅读上述文档:说明vue不支持二者放到同一个标签中使用 否则真的会失 ...
最新文章
- iOS通过CAShapeLayer和UIBezierPath画环形进度条
- bn层Expected more than 1 value per channel when training, got input size torch.Size
- dataset__getitem___一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系
- 数学图形之克莱因瓶(klein bottle)
- 如何补救数据中心电缆
- XmlHttpRequest 对象详解
- oracle查询cpu占用率高,解决oracle进程CPU占用过高问题
- c++ n次方函数_高中数学必修一二次函数与幂函数试题及答案
- xcode工程编译错误:The maximum number of apps for free development profiles has been reached.
- css连续选取几个li_CSS高级选择器:nth-child()应用大全
- Pannellum:实例之一个简单的例子
- 孙鑫VC学习笔记:第一讲 Windows程序内部运行原理
- 妈妈!我也会做植物大战僵尸啦!
- keil出现stdin(‘-’)combined with other files
- Cadence Allegro自动放置所有元件图文教程及视频演示
- 高二会考计算机操作题试题及答案,2017高二数学会考试题及答案_高二会考答案(数学)(5)...
- DaoCloud道客云原生开源项目KLTS,全称为Kubernetes Long Term Support,为Kubernetes早期版本提供长期免费的维护支持
- 智能手机相机镜头的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- 当存储遇到开源 可以先从冷数据着手
- CMakeLists.txt 详解
热门文章
- 自定义控件之下拉刷新列表
- [ROC-RK3568-PC] [Firefly-Android] 10min带你了解UART的使用
- mysql simpleconsumer_SimpleMessageListenerContainer:Consumer raised exception
- 交互式数据可视化_我如何构建一个交互式仪表板Web应用程序以可视化拳击数据...
- 【CSP-S2019模拟】09.25比赛总结
- log 1用计算机怎么打开,log是什么?log怎么打开?
- vscode打开项目从中文界面变成英文界面的问题
- uni-app 报错:代码使用了scss/sass语言,但未安装相应的编译器插件,请前往插件市场安装该插件
- signature=506ccff074d130c2e8d4e3268d3b44f1,Secure proxy signature schemes from the Weil pairing
- pat 甲级 A1008 Elevator