Android Jetpack之Room

Room简介

前言
本篇中数据库调试工具使用debug-db,没接触过的可以看这里介绍

https://blog.csdn.net/jinjin10086/article/details/103919983

Room综述
Room是Google Jetpack组件中的一员,是一种数据库的ORM框架,该库 在SQLite 的基础上提供了一个抽象层,让用户能够在充分利用 SQLite
的强大功能的同时,获享更强健的数据库访问机制。
Room相关的类
注解相关
  1. @Entity注解:标识数据库映射关系的类,可以指定表名等,不指定的话默认表=名和类名一致,索引等信息。
  2. @PrimaryKey注解:指定主键,可设置自动增长等属性。
  3. @ColumnInfo注解:指定列信息,如列名等信息。
  4. @Ignore注解:标识忽略此属性,不对应生成数据库字段。
  5. @Dao注解:标识Dao层注解,编译时候会生成该接口或抽象类的实现。
  6. @Insert注解:标识该抽象方法为插入数据库,入参为Entity注解标注的类对象。
  7. @Query注解:标识该抽象方法为查询的方法(表面),需传入sql语句,其实sql语句可以实现增删改查的操作,也就是说可以实现常用全部操作。
  8. @Delete注解:标注该方法为删除的方法,入参为Entity注解标注的类对象。
  9. @Update注解:标注该方法为更新的方法,入参为Entity注解标注的类对象。
  10. @Database注解:标注该类为数据库操作类,一般为单例对象,入参entities为对应映射的kclass对象集合,verson处理数据库升级相关,通过此类可以拿到相关数据库操作的dao对象,进行相关的数据库操作。
类相关
  1. RoomDatabase.java类:抽象类,处理数据库初始化,及dao对象的生成相关操作,目前操作只需要接触到这个类即可。
  2. Room.java类:类,内部采用Builder模式,用于生成具体的RoomDatabase的子类对象

Room使用

简单使用
  1. 依赖引入,如下:
     def room_version = “2.2.3”
    implementation "androidx.room:room-runtime:$room_version”
    kapt  "androidx.room:room-compiler:$room_version”
  1. ORM映射类创建,如下
    @Entity
    class PersonBean constructor(){
    
        constructor(name:String,age:Int):this(){
            this.name = name
            this.age = age
        }
    
        @PrimaryKey(autoGenerate = true)
        var id:Int? = null
        var name:String? = null
        var age:Int? = null
    
        @Ignore
        var sex:Int?=null
    
        override fun toString(): String {
            return "PersonBean(id=$id, name=$name, age=$age, sex=$sex)”
        }
    }
  1. Dao创建(对应增删改查四个方法)
    @Dao
    abstract class PersonDao {
    
        @Insert
        abstract fun insert(person: PersonBean)
    
        @Delete
        abstract fun delete(person: PersonBean)
    
        @Update
        abstract fun update(person: PersonBean)
    
        @Query("SELECT * FROM PersonBean”)
        abstract fun getPersonList():MutableList
    
    }
  1. RoomDatabase子类创建,持有dao的引用,代码如下:
    @Database(entities = [PersonBean::class], version = 1)
    abstract class PersonRoomDatabase : RoomDatabase() {
    
        abstract fun personDao(): PersonDao
    
        companion object {
    
            @Volatile
            private var instance: PersonRoomDatabase? = null
    
            fun getPersonRoomDatabase(context:Context):PersonRoomDatabase{
                if (null == instance){
                    synchronized(PersonRoomDatabase::class){
                        if (null == instance){
                            instance = Room.databaseBuilder(context.applicationContext,PersonRoomDatabase::class.java,"db_test").allowMainThreadQueries().build()
                        }
                    }
                }
                return instance!!
            }
    
        }
    
    }

  1. 调用,插入,调用如下:
    class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_room)
        roomTest()
    }

    private fun roomTest() {
        val personDao = PersonRoomDatabase.getPersonRoomDatabase(this).personDao()
        val person = PersonBean("张大爷”,80)
        personDao.insert(person)
        Log.d(Common.TAG,"插入数据:$person”)
        val person1 = PersonBean("小张”,8)
        personDao.insert(person1)
        Log.d(Common.TAG,"插入数据:$person1”)
    }

}

运行日志:


日志1

查询数据库数据如下,显然已经插入成功


数据1

数据库名称对应RoomDatabase子类中指定的数据库名称,表明对应映射对象的类名,数据和日志一直,插入了两条数据
  1. 调用,删除,调用如下(这里只需传入id即可,因为删除的时候只用到id):
       val personBean = PersonBean()
        personBean.id = 1
        personDao.delete(personBean)

查询数据库如下,显然已经删除成功


数据2

7.调用,更新,调用如下:

     val personBean = PersonBean("小张来了”,23)
        personBean.id = 2
        personDao.update(personBean)

查询数据如下,显然已经更新成功


数据3
  1. 调用,查询,如下:
      var personList: MutableList = personDao.getPersonList()
        Log.d(Common.TAG,"共有${personList.size}个人”)
        personList.forEach {
            Log.d(Common.TAG,it.toString())
        }

日志如下:


日志2

查询数据如下,和日志一致:


数据4
扩展使用
@Query实现增删改

和之前的增删改效果一致,代码如下:

    @Query("insert into PersonBean values (:id,:name,:age)”)
    fun insertQuery(id:Int?,name:String?,age:Int?)

    @Query("delete from PersonBean where id = :id”)
    fun deleteQuery(id:Int?)

    @Query("update PersonBean set name = :name , age = :age where id= :id”)
    fun updateQuery(id:Int?,name:String?,age:Int?)

至于为什么没有使用person作为参数实现这个过程,在@Query的注释中已经说得很清楚了,只支持名字匹配识别


注释1
多参数插入、删除、更新操作
插入代码如下(更新和删除类似):
    //dao
    @Insert
    fun insert(vararg person: PersonBean)
    //调用
     val person = PersonBean("张大爷", 80)
     val person1 = PersonBean("张大妈", 79)
     personDao.insert(person,person1)
     Log.d(Common.TAG, "插入数据:$person”)
     Log.d(Common.TAG, "插入数据:$person1”)

     var personList: MutableList = personDao.getPersonList()
     Log.d(Common.TAG, "共有${personList.size}个人”)
     personList.forEach {
         Log.d(Common.TAG, it.toString())
     }    

日志如下:


日志3

查询数据如下,和日志一致:


数据5
条件查询

基本数据如下:


数据

查询Dao代码如下:

    @Query("select * from PersonBean where id= :id”)
    fun findById(id:Int?): MutableList

    @Query("select * from PersonBean where age > :age”)
    fun findByAge(age:Int?): MutableList

    @Query("select * from PersonBean where name like :name”)
    fun findByNameRule(name: String?): MutableList

1、findById方法id 传入3 ,结果如下:


结果5

2、findByAge方法 age传入16,结果如下:


结果4

3、findByNameRule方法
name传入”张%”

结果如下:


结果1

name传入”%张”
结果2

name传入"%张%”
结果如下:
结果3
Room升级
场景:
1、增删表、增删字段
步骤:
1、改变版本号,在RoomDatabase的子类,如下改变version即可:
@Database(entities = [PersonBean::class,Student::class], version = 2)
2、如果是增加表,则相应的增加、减少entities数组的内容
3、增加Migration,代码如下:
    Room.databaseBuilder(context.applicationContext,PersonRoomDatabase::class.java,”db_test”)
                            .addMigrations(object: Migration(1,2){
                                override fun migrate(database: SupportSQLiteDatabase) {
                                    //此处为增删表、增删字段的sql书写处
                                    database.execSQL("CREATE TABLE IF NOT EXISTS `Student` (“ +
                                            "`id` INTEGER PRIMARY KEY AUTOINCREMENT,” +
                                            "`name` TEXT,” +
                                            "`age` INTEGER “ +
                                            ");”)
                                }
                            })
                            .allowMainThreadQueries().build()
其实增加表的时候Sql可以在此处找到,目录如下
目录

内容如下:


内容

删除的语句也能找到,如下:

升级过程可以实现串式升级,即现在安装1版本,目标4版本,添加的迁移器是Migration(1,2),Migration(2,3),Migration(3,4),直接
升级是可以成功的,没有问题,不需要添加Migration(1,4),Migration(2,4)等迁移器。

关于Room使用,暂时先到此处,不做过多深入
实现过程
本来想分析一下创建表到数据操作的实现过程,限于篇幅与时间,后续再补上吧

注意

1、写Bean的时候一定要注意按照规范写 不然容易出现错误如下,没有具体报错的地方,其实是在编译阶段生成代码的时候报错了:


错误1

kotlin代码如下:

    @Entity(tableName = “tb_person”)
    class Person constructor(){

        constructor(name:String,age:Int):this(){
            this.name = name
            this.age = age
        }
    
        @PrimaryKey(autoGenerate = true)
        var id:Int? = null
        var name:String? = null
        var age:Int? = null
    
        override fun toString(): String {
            return "Person(id=$id, name=$name, age=$age)”
        }
    
    }

2、select的结果是列表,要注意,不写返回值编译时不能通过的。
3、数据库升级之后,再安装低版本会报错,不能覆盖安装,需要卸载之后重新安装,不然会报错如下:

报错

提示高版本到低版本的合并操作没有添加合并器,记住:
卸载重新安装,卸载重新安装,卸载重新安装

源码

源码链接:源码

总结

1、关于Jetpack Room的介绍先到此处,后续可能会继续深入。

2、自勉,实践出真知,blog记录自己成长,也能帮助一些需要该方面知识的人,不能没有经过验证的结论直接网上帖,那样难免会坑自己,
也可能坑别人,就像上述的Room数据库升级操作 ,串式升级验证过,卸载直接安装高版本也验证过,验证通过的,当然如果因为一些特殊因素
(如环境等可能会导致问题),那就再做讨论验证。

3、Room总的用起来总的感觉良好:
    
    只需要在dao接口写方法声明就可以,通过PersonRoomDatabase拿到dao对象可以实现增删改查操作
    
    插入、更新、删除都很简单,注解操作就能实现,当然你要写sql也没人拦着,支持多参数操作也比较方便。
    
    查询操作是需要些sql的,参数支持名称识别,上述说过,总体也是很方便的
    
    在数据库升级的时候感觉稍显麻烦,需要自己添加迁移操作,需要些sqk语句(如增删表、增删字段等),之前用litepal是不需要写这些的,
    只需要更改版本号即可。

4、注意中写到的注意点都是我在使用时候踩到的坑记录下来,避免以后再踩,也给后来者一点提示,能少踩点坑。

你可能感兴趣的:(Android Jetpack之Room)