Room简介
Room 是对Sqlite 的二次封装,利用APT注解处理器技术自动生成代码,方法我们更能流畅易用的访问数据库
**
Room的使用配置
在项目build.gradlew
//room
implementation "androidx.room:room-ktx:2.2.5"
kapt "androidx.room:room-compiler:2.2.5"
Room的使用
**
1, 先定义个数据库类,继承 RoomDatabase,并且该类是抽象类
2.每个数据库都有对应的表,每个表其实数据bean, 而用 @Entry 表示它就是一个数据表
3.@dao,对应的数据表提供给外部增删改查就是使用的对应的dao 去增删改查,dao类他是个接口类
4.在数据库类中设置抽象方法提供对方的表的dao类
//一个数据库抽象类继承RoomDatabase用@Database表示是数据库
//一个数据库包含多张表
//entities: 各个实例bean 类 version: 数据库版本号 exportSchema: 是否需要导出 Schema
//在数据库中用抽象方法把对应的表的dao提供给外界去利用dao 增删改查对应的表数据
@Database(entities = [Student::class,Teacher::class], version = 1, exportSchema = false)
abstract class ClassDataBase :RoomDatabase() {
abstract fun getStudentDao():StudentDao
abstract fun getTeacherDao():TeacherDao
}
//用到@Dao 表示一个接口类,这个接口dao 就是提供给外面对数据库对应的表进行增删改查的
//所以有对于的增删改查方法和注释,而查询用的也是基本的sql语句
@Dao
interface StudentDao {
//删除的Student可能有多个,所以这里用vararg 定义
@Insert
fun insertStudents(vararg item: Student)
@Update
fun updateStudents(vararg item: Student)
@Delete
fun deleteStudents(vararg item: Student)
//对名字是参数xxx的对象,把他们的age都更新
@Query("UPDATE Student SET age = :age WHERE name = :name")
fun updateStudentsByName(name: String, age: Int)
//删除名字是参数xxx,并且 age 是参数的xxx 的对象
@Query("DELETE FROM Student WHERE name = :name AND age = :age")
fun deleteStudentByNameAndAge(name: String, age: Int)
@Query("DELETE FROM Student")
fun deleteAllStudents()
//这个getAllStudent方法如果返回的是Livedata,那么当数据库的数据发生改变的时候
//LiveData的观察者就会监听到,其中就包含Databinding,然后Databinding就会驱动界面去更新UI
//@Query()括号内就是基本的sql语言,表示,根据id 查找Student
@Query("SELECT * FROM Student ORDER BY id ASC")
fun getAllStudent(): LiveData<List<Student>>
}
//一个数据bean 用@Entity代表他是一个张表
@Entity(tableName = "Student")
class Student () {
//主键,自增
@PrimaryKey(autoGenerate = true)
var id: Int = 0
//如果不使用ColumnInfo,则使用字段名作为列名
@ColumnInfo(name = "name")
var name: String = ""
@ColumnInfo(name = "age")
var age: Int = 0
constructor(_name: String, _age: Int) : this() {
name = _name
age = _age
}
constructor(_id:Int,_name: String, _age: Int) : this() {
id = _id
name = _name
age = _age
}
}
class MyRepository @Inject constructor(@ApplicationContext val context: Context) {
//创建数据库并获取对应表的Dao,name是数据库的名字
private var classDataBase: ClassDataBase =
Room.databaseBuilder(context, ClassDataBase::class.java, "ClassDataBase").build()
//从数据库获取对应表的Dao
private var studentDao:StudentDao = classDataBase.getStudentDao()
fun insertStudents(item: Student){
studentDao.insertStudents(item)
}
fun updateStudents(item: Student){
studentDao.updateStudents(item)
}
fun deleteStudents(item: Student){
studentDao.deleteStudents(item)
}
fun deleteAllStudents(){
studentDao.deleteAllStudents()
}
fun getAllStudent(): LiveData<List<Student>> {
return studentDao.getAllStudent()
}
}
注意,在数据库操作中,
如果你单纯的 调用
val student = Student("zjs", 30)
studentDao.updateStudents(student)
val student = Student("zjs", 30)
studentDao.updateStudents(student)
去更新或者删除一个对象,那么是更新不了也删除不了的。
因为数据库是根据你对象的主键id 去找到对应的数据然后进行更新或者删除
所以你的这个对象需要有对应的id
val student = Student(1,"zjs", 30)
studentDao.updateStudents(student)
val student = Student(2,"zhaojiasheng", 30)
studentDao.deleteStudents(student)
而在业务上我们往往是根据对象字段去进行更新或者删除。
所以我们需要根据业务在Dao类上增加一些需要的方法:
//对名字是参数xxx的对象,把他们的age都更新
@Query("UPDATE Student SET age = :age WHERE name = :name")
fun updateStudentsByName(name: String, age: Int)
//删除名字是参数xxx,并且 age 是参数的xxx 的对象
@Query("DELETE FROM Student WHERE name = :name AND age = :age")
fun deleteStudentByNameAndAge(name: String, age: Int)
val student = Student("zjs", 30)
//把名字是zjs的对象,年龄都更新为30
studentDao.updateStudentsByName(student.name,student.age)
val student = Student("zjs", 25)
//把名字是zjs并且年龄为25的都删掉
studentDao.deleteStudentByNameAndAge(student.name,student.age)
Room要求数据操作不能在UI线程中,需要在子线程中进行操作, 所以直接在主线程中调用 insert update delete
这三个方法,会直接崩溃,但你调用query是不会崩溃的,不过 query方法如果是大量数据查询,最好也还是放在
子线程中
lifecycleScope.launch(Dispatchers.IO){
studentDao.insertStudents(item)
studentDao.updateStudents(item)
studentDao.deleteStudents(item)
studentDao.deleteAllStudents()
}
**
Room数据库查看
**
在设备data/data/包名下 有你创建的数据库
把这3个文件导出来到桌面,然后用SQLiteStudio打开第一个ClassDataBase文件,然后选择对应的表可查看数据
**
升级数据库版本的操作
**
一般升级的情况是比如说要在原来的表上增加字段
比如
表上增加字段
//一个数据bean 用@Entity代表他是一个张表
@Entity(tableName = "Student")
class Student () {
//主键,自增
@PrimaryKey(autoGenerate = true)
var id: Int = 0
//如果不使用ColumnInfo,则使用字段名作为列名
@ColumnInfo(name = "name")
var name: String = ""
@ColumnInfo(name = "age")
var age: Int = 0
//增加height字段
@ColumnInfo(name = "height")
var height :Int =0
constructor(_name: String, _age: Int) : this() {
name = _name
age = _age
}
}
//把数据库的版本升级2
@Database(entities = [Student::class,Teacher::class], version = 2, exportSchema = false)
abstract class ClassDataBase :RoomDatabase() {
abstract fun getStudentDao():StudentDao
abstract fun getTeacherDao():TeacherDao
}
设置一个 migration,这里,1,代表数据库版本从1 升级到2
把migration addMigrations 到数据库
var migration_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
//在这里使用sql完成对表的字段修改
//这里的sql表示增加了height字段,并且这个字段不能为null,默认是0
database.execSQL("alter table student add column height integers not null default 0")
}
}
// 把 migration .addMigrations 到数据库
private var classDataBase: ClassDataBase =
Room.databaseBuilder(context, ClassDataBase::class.java, "ClassDataBase")
.addMigrations(migration_1_2)
.build()