文章目录
简介
Room是Google官方推出的Architecture Components中的一个持久性数据库,提供了基于SQLite的抽象层,可以在充分利用SQLite功能的前提下流畅的访问数据库。(官方详细介绍,需要翻墙)
相信早期使用过SQLite进行开发的小伙伴都深有体会SQLite使用起来有多麻烦:SQLite没有提供编译时的sql检查机制,即使写错了也可以通过编译,需要在编译出来之后去验证,同时,在进行CRUD操作时需要手动写很多sql与bean之前转换的无脑式代码,费时费力。
所以后面催生出了很多类似于greenDao、Realm等优秀的第三方开源数据库框架,但终究不是官方的,全靠个人在升级维护,在考虑便捷性、性能以及后期升级拓展等方面因素的情况下,个人觉得Room还是挺不错的一个选择,毕竟有Google的研发团队在支撑。扯远了哈,这都是题外话了,下面我们来看看Room有什么优点。
优点
- 编译时检查。Room会在编译期去检查验证sql的正确性,这样就不会出现运行时出现严重错误的风险;
- 使用便捷。只需简单的三步少量的代码即可实现常规的CDUR;
- 支持LiveData;
- 与Rxjava结合可以实时监听数据变化。
Demo效果及地址
Demo中包括了常见的增、删、改、查以及数据库升级等功能,还包括了结合Rxjava监听数据变化的功能。
Demo地址:https://github.com/jianlin00000/RoomDemo
创建步骤
添加依赖
在app/build.gradle中添加如下依赖:
//运行时和编译时依赖
implementation 'android.arch.persistence.room:runtime:1.1.1'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
//支持Rxjava2
implementation 'android.arch.persistence.room:rxjava2:1.1.1'
//测试支持
androidTestImplementation 'android.arch.persistence.room:testing:1.1.1'
1.使用@Entity创建表
@Entity(tableName = "student") //设置表名
public class Student {
@NonNull //主键不能为null,必须添加这个注解
@PrimaryKey(autoGenerate = true) //主键是否自动增长,默认为false
public long id;
@ColumnInfo
public int age;
@ColumnInfo(name = "name") //可以通过设置name =xxx 的方式重新命名字段
public String studentName;
@ColumnInfo
public int age;
@Embedded
public CourseScore course;
public Student() {
}
@Ignore //只允许有一个主构造方法,其他构造方法要使用@Ignore设置为忽略
public Student(@NonNull int id, int age, String name, CourseScore course) {
this.id = id;
this.age = age;
this.name = name;
this.course = course;
}
}
public class CourseScore {
public int chinese;
public int english;
public int math;
@Ignore
public int sports; //这个字段将被忽略,不会被映射到表中
public CourseScore(int chinese, int english, int math) {
this.chinese = chinese;
this.english = english;
this.math = math;
}
}
说一下类中出现的几个注解的意思:
@Entity
在Room中每个表对应一个具有 @Entity 注解的JavaBean,也就是说一个bean对应一张表;
@PrimaryKey
所有的CRUD操作都是根据主键进行操作的,所以每个表要求必须有一个主键,主键字段通过 @PrimaryKey 进行标识,因为主键不能为空,所以要求必须添加android.support.annotation注解库中的 @NonNull 注解 ,否则编译报错。主键默认是不自增,因为主键的类型并不限于long、int等类型,String等类型也是可以的;
@ColumnInfo
bean中每一个具有@ColumnInfo 注解的字段会被映射为表中的一个字段,映射字段可以更改,默认直接使用当前字段,另外如果字段为private修饰的则必须提供对应的getter、setter方法,public字段修饰则不用;
@Ignore
顾名思义,该注解是用于设置忽略的,每个表对应的JavaBean只能有一个主构造方法,若还有其它的构造方法则必须使用@Ignore注解进行标识;
@Embedded
这也是一个很方便实用的注解,这个注解可以将普通JavaBan中的字段也引入到对应的表中,查询结果会自动为对应的bean,不需要的字段可以使用@Ignore进行标识
2.使用@Dao,创建操作数据库的接口
@Dao
public interface StudentDao {
//-------------------------插入--------------------------------------------
/**
* 插入操作,若已存在相同的主键的数据则直接覆盖
* 返回值也可以设为void
* @param student
* @return 插入的row id
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
Long insert(Student student);
/**
* 同上
* @param student
* @return 插入的row id 集合,也可以设置为Long[]返回值
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
List<Long> insert(Student ... student);
/**
* 同上
* @param list
* @return 插入的row id 集合
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
List<Long> insert(List<Student> list);
//-------------------------更新--------------------------------------------
/**
* 更新操作
* @param student
* @return 更新成功的数量
*/
@Update
int update(Student student);
/**
* 同上
* @param student
* @return 更新成功的数量
*/
@Update
int update(Student... student);
//-------------------------查询--------------------------------------------
/**
* 查询指定名字的数据
* @param name
* @return
*/
@Query("SELECT * FROM student WHERE name=:name")
Student getByName(String name);
/**
* 查询所有数据
* @return
*/
@Query("SELECT * FROM student")
List<Student> loadAll();
/**
* 查询所有数据
* 与Rxjava的Flowable结合,可以进行数据变化监听
* @return
*/
@Query("SELECT * FROM student")
Flowable<List<Student>> getAll();
//-------------------------删除--------------------------------------------
/**
* 根据主键进行删除
* @param student
* @return 删除成功的数量
*/
@Delete
int delete(Student student);
@Delete
int delete(Student... student);
@Query("DELETE FROM student")
int deleteAll();
/**
* 删除指定名字的数据
* @param name
* @return
*/
@Query("DELETE FROM student where name=:name")
int deleteByName(String name);
}
到这一步可以说已经完成了将近80%了,是不是很便捷,我们来看一下DAO类中出现的一些注解:
@Dao
DAO是数据库访问对象,要变成一个数据库访问对象必须在类的声明上面添加 @Dao 注解,并且根据官方文档的要求,DAO必须是一个interface 或者 abstract class,然后在里面写操作数据库的相关接口,主要的是通过在方法上添加 @Insert、@Update、@Query、@Delete中的某一个注解实现对应的“插入、更新、查询、删除”操作。注意,DAO类中这些操作都是阻塞的,使用要在异步线程中使用。
@Insert
插入操作中出现了 “@Insert(onConflict =