Room的使用

本文介绍了Room,一个基于SQLite的Android数据存储库,如何通过APT注解处理器简化数据库操作。讲解了如何配置Room,定义数据库类、表、DAO以及迁移数据库版本的过程,强调了在UI线程之外进行数据库操作的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值