Room的使用
- @Entity:表示数据中的表
- @DAO:数据库操作对象
- @Database数据库:必须是扩展RoomDatabase的抽象类。在注解中添加与数据库关联的数据表。包含使用@Dao注解标记的类和抽象方法
集成
implementation("androidx.room:room-runtime:2.4.3")
kapt("androidx.room:room-compiler:2.4.3")
@Entity
@Entity注解接受一个tableName参数,这个参数表示这个对象将会存储在哪张表中
Room规定每个被@Entity修饰的类都必须有一个主键@PrimaryKey
@PrimaryKey注解中autoGenerate参数表示主键是否可以通过数据库自行维护,一般是自增
@ColumnInfo注解是注解在成员变量上,表示这个成员变量会被存入哪一列,name参数表示列名,defaultValue表示默认值
@Ignore表示这个变量在存储数据库的时候会被忽略
@Embedded让当前字段也映射进表中,要求当前对象也需要用@Entity注解标记需要在注解上标记@SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)否则编译会有报错
@SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)表示该成员变量中的主键将会被忽略
/**
* @PrimaryKey(autoGenerate = true)表示主键,其中参数autoGenerate表示主键可以由数据库自动生成
* @ColumnInfo(name = "cacheId", defaultValue = "1")表示列的名字为cacheId, 默认值为1
* @Ignore表示会忽略这个字段,不进行记录
* @Embedded 让当前对象中的字段也映射进入表中,要求当前对象也需要用@Entity注解标记
* @SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)表示该对象中的主键将会失效
*/
@Entity(tableName = "room_test_table")
class RoomTestTable{
@PrimaryKey(autoGenerate = true)
var id : Long = 0
@ColumnInfo(name = "cacheId", defaultValue = "1")
var cache_id = 0
@Ignore
var bitmap: String = ""
@SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)
@Embedded
lateinit var user: User
@ColumnInfo(name="test_list")
lateinit var testList : MutableList<String>
}
@Entity(tableName = "user_table")
class User{
@PrimaryKey(autoGenerate = false)
lateinit var userName : String
@ColumnInfo(name = "userage")
var userAge : Int = 0
}
@DAO
@DAO注解需要标记在接口上,内部是实现数据库增删改查的功能
Room本身支持LiveData作为返回值
@Dao
interface TestDao {
@Query("SELECT * FROM room_test_table")
fun getAll() : List<RoomTestTable>
@Query("SELECT * FROM room_test_table WHERE userName = :userName")
fun getDataByName(userName : String) : RoomTestTable
//可以通过LiveData 以观察者的形式获取数据库数据,可以避免不必要的npe,
// 更重要的是他可以监听数据库的变化,一旦发生了insert update delete, room会自动读取表中最新的数据
@Query("SELECT * FROM room_test_table")
fun getLiveDataAll() : LiveData<List<RoomTestTable>>
@Query("SELECT * FROM room_test_table WHERE userName = :userName")
fun getLiveDataDataByName(userName : String) : LiveData<RoomTestTable>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg roomTestTable: RoomTestTable)
@Delete
fun delete(roomTestTable: RoomTestTable)
@Query("DELETE FROM room_test_table WHERE id = :id")
fun delete(id : Long)
}
@Database @TypeConverters
@Database接口需要标记在抽象类上
@Database(entities = [RoomTestTable::class], version = 5, exportSchema = true, autoMigrations = [AutoMigration(from = 4, to = 5)])
//转换器,Room中不能被数据库存储的类型,可以通过转换器变成可以被存储的状态,并且在查询后自动转换类型
@TypeConverters(TestConverters::class)
abstract class TestDataBase : RoomDatabase() {
abstract fun testDao() : TestDao
}
class TestConverters(){
@TypeConverter
fun listToString(list : MutableList<String>) : String{
Log.d("TypeConverters", list.toString())
return list.toString()
}
@TypeConverter
fun stringToList(source: String) : MutableList<String>{
val listStr = source.replace("[", "").replace("]", "")
return listStr.trim().split(",").filter { it.isNotEmpty() }.toMutableList()
}
}
@TypeConverters转换器,当Room中不能存放的对象在存放到表中会经过转换器转换。转化器的方法名不重要,重要的是入参和出参,在上面的Entity中testList是不能被数据库存储的,当存储到数据控中会经过转换器
fun listToString(list : MutableList<String>) : String
方法转换成String存入数据库。当查询出数据后会自动经过
fun stringToList(source: String) : MutableList<String>
方法转化成我们需要的类型。
注意在database抽象类上标记的为@TypeConverters 在转换器中标记的为@TypeConverter
数据库管理类与数据库升级
Room数据库可以记录每个版本的sql,并用于自动升级
在项目的gradle中加入如下代码
defaultConfig {
applicationId "com.example.tdframe"
//生成数据库SQL语句
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true",
"room.expandProjection":"true"]
}
}
}
之后每个版本的数据库都会生成相应的文件
数据库生成的文件记得保存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9g5gZJGq-1665969811492)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a2ea69f04c324b2399b8df8e7664ebf1~tplv-k3u1fbpfcp-watermark.image?)]
在@Database注解上开启exportSchema,和autoMigrations
AutoMigration注解接受两个参数,分别from和to从哪个数据库迁移数据到目标版本
@Database(entities = [RoomTestTable::class], version = 5, exportSchema = true, autoMigrations = [AutoMigration(from = 4, to = 5)])
//转换器,Room中不能被数据库存储的类型,可以通过转换器变成可以被存储的状态,并且在查询后自动转换类型
@TypeConverters(TestConverters::class)
abstract class TestDataBase : RoomDatabase() {
abstract fun testDao() : TestDao
}
object DBManager {
lateinit var dataBase: TestDataBase
fun init(context: Context) {
//allowMainThreadQueries允许数据库在主线程上进行查询操作
//
dataBase = Room.databaseBuilder(context, TestDataBase::class.java, "TEST_DATA_BASE")
.fallbackToDestructiveMigration()
//允许数据库在主线程上进行查询操作
//.allowMainThreadQueries()
//指定数据库查询数据时候的线程池
//.setQueryExecutor { }
//升级策略
//.addMigrations()
.build()
}
}
之后修改@Entity修饰的类,数据库将会自动升级
@Entity(tableName = "room_test_table")
class RoomTestTable{
@PrimaryKey(autoGenerate = true)
var id : Long = 0
@ColumnInfo(name = "cacheId", defaultValue = "1")
var cache_id = 0
@Ignore
var bitmap: String = ""
@SuppressWarnings(RoomWarnings.PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED)
@Embedded
lateinit var user: User
@ColumnInfo(name="test_list")
lateinit var testList : MutableList<String>
//数据库升级后添加的列名
@ColumnInfo(name = "add_column", defaultValue = "empty")
lateinit var addColumn : String
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XuqxckBS-1665969811493)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/149096c5ab9b4814b32341e39cf27e2d~tplv-k3u1fbpfcp-watermark.image?)]
使用sqlite查看数据库
我们在查看数据的时候需要使用root后的手机或者使用AndroidStudio自带的虚拟机
虚拟机我们需要使用带GoogleAPIs的才能获取root权限
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8xRC0fd-1665969811493)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/22afb33ebb824a719b47b04fdc1df8a3~tplv-k3u1fbpfcp-watermark.image?)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uA2qzWcA-1665969811494)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c189398ae67545ba83f115bd8f4e3059~tplv-k3u1fbpfcp-watermark.image?)]
下面是sqlite3的一些常用命令
.databases
列出附加到数据库的数据库和文件
.echo ON|OFF
打开/关闭 命令行回显
.exit
退出该命令行
.explain ?ON|OFF?
以合适的方式显示表头, 不带参数则为开启
.header ON;OFF
是否显示表头, 和 .explain 差别不是很大
.help
显示帮助信息
.import FILE TABLE
从文件中导入表
.indices ?TABLE?
显示索引
.load FILE ?ENTRY?
加载一个扩展库
.log FILE|off
是否记录日志,文件可以是标准输出/输入
.mode MODE ?TABLE?
设置输出模式, 模式可以是以下几种:
csv 以逗号分隔的值
column 表头左对齐(参见 .width)
html 显示 HTML 代码
insert SQL插入语句
line 一行一个值
list 值用 string 分隔
tabs 以 tab 分隔的值
tcl TCL 列表元素
.nullvalue STRING
以 STRING 代替 NULL 值的输出
.output FILENAME
输出到文件, 而不是显示在屏幕上
.output stdout
输出到屏幕上
.prompt MAIN CONTINUE
替换默认的命令提示信息, 默认就是 sqlite>
.quit
退出命令行
.read FILENAME
执行 FILENAME 中的 SQL
.restore ?DB? FILE
从文件中还原数据到表, 默认表为 main
.schema ?TABLE?
显示 CREATE 语句
.timeout MS
在 MS 时间内尝试打开被锁定的表
.vfsname ?AUX?
显示 VFS 栈信息
.width NUM1 NUM2 …
设置 column 模式中的列的宽度
.timer ON|OFF
显示CPU时间