6.Room

Room是什么?

1
2
Room 是一个轻量级 orm 数据库,本质上是一个SQLite抽象层,但是使用起来会更加简单,类似于Retrofit库。Room 在开发阶段通过注解
的方式标记相关功能,编译时自动生成响应的 impl 实现类

ORM映射关系设计与详解

1
2
3
对象关系映射(英语:Object Relational Mapping,简称ORM,或0/RM,或0/R mapping),是一种程序设计技术,用于实现面向对象编程
语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。如今已有很多免费和
付费的ORM产品,而有些程序员更倾向于创建自己的ORM工具。
image-20231110141607880

Room使用:

1
2
implementation "androidx.room:room-runtime:2.2.3"
annotationProcessor "androidx.room:room-compiler:2.2.3"
1
2
3
4
官网的文档也指出,我们需要创建这三个文件,才能正式的使用Room:
1.Entity:普通Java Bean类
2.DAO:定义一个接口类
3.Room Database:定义一个抽象类,并继承Room Database

1.定义Entity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* 1.Entity类需要使用@Entity注解标注,并且其中的tableName即数据表名,可以改为自己想取的名字
* 2.构造函数:构造函数可以允许多个,但只允许只有一个不加@Ignore注解,其它的都得加上@Ignore注解,实际运行发现,若多个构造函数不
* 加@Ignore,将无法通过编译。至于多个构造函数的存在是因为CRUD的特性决定的,例如删除,只需要id主键就行了。因此提供了多个构造
* 函数
* 3.Getter和Setter方法:这些方法是必须要的,否则无法对对象属性进行读取或修改
*/

//Entity类需要使用@Entity注解标注,并且其中的tableName即数据表名,可以改为自己想取的名字
@Entity(tableName = "StudentDao")
public class StudentEntity {
/**
* 使用@PrimaryKey声明为主键,并且允许自动生成
* 使用@ColumnInfo表明这个属性是表中的一列列名,并可以指明列的名称
*/
@PrimaryKey(autoGenerate = true)//autoGenerate = true 使得主键的值自动生成
@ColumnInfo(name = "id")
private int id;
@ColumnInfo
private String name;
@ColumnInfo
private String pwd;
@ColumnInfo
private int age;


public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPwd() {
return pwd;
}

public void setPwd(String pwd) {
this.pwd = pwd;
}
}

2.定义 Dao:

DAO类主要是提供对数据库的访问方法,是一个接口类。通过将SQL语句与方法结合的方式,降低结构的复杂程度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* DAO层接口,需要添加@Dao注解声明
* 所有的操作都以主键为依托进行
*/
@Dao
public interface StudentDao {

/**
* 查询所有的数据,返回List集合
* @return
*/
@Query("Select * from StudentDao")
List<StudentEntity> getAllStudentList();

/**
* 传递参数的集合,注意 Room通过参数名称进行匹配,若不匹配,则编译出现错误
* @param personId
* @return
*/
@Query("select * from StudentDao where id in (:personId)")
List<StudentEntity> getStudentById(int[] personId);

/**
* 返回一定条件约束下的数据,注意参数在查询语句中的写法
* @param minAge
* @param maxAge
*/
@Query("select * from StudentDao where age between :minAge and :maxAge")
List<StudentEntity> getStudentByAgeRange(int minAge, int maxAge);

/**
* 插入数据,onConflict = OnConflictStrategy.REPLACE表明若存在主键相同的情况则直接覆盖
* 返回的long表示的是插入项新的id
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insertStudent(StudentEntity studentEntity);

/**
* 更新数据,这意味着可以指定id然后传入新的person对象进行更新
* 返回的long表示更新的行数
*/
@Update
int updatePerson(StudentEntity studentEntity);


/**
* 删除数据,根据传入实体的主键进行数据的删除。
* 也可以返回long型数据,表明从数据库中删除的行数
*/
@Delete
int deletePerson(StudentEntity studentEntity);
}

3.Room Database类构建

得益于Room的良好封装,这个类的构建步骤只有两步,非常的简单。

  • 创建一个StudentDatabase抽象类并继承自RoomDatabase类
  • 声明一个StudentDao()的抽象方法并返回StudentDao的对象引用
1
2
3
4
5
6
7
/**
* 指明是需要从那个class文件中创建数据库,并必须指明版本号
*/
@Database(entities = {StudentEntity.class}, version = 1)
public abstract class StudentDataBase extends RoomDatabase {
public abstract StudentDao studentDao();
}

这样就完成了对RoomDatabase的构建,这里要注意引入@Database注解,它表明需要与哪一个Entity类产生联系,生成对应的数据库表。并且version版本号是一个必填字段,在这里,我们定义为1即可。

4.在Activity中操作Room

这里要特别注意的是:虽然Room可以通过调用.allowMainThreadQueries()方法允许在主线程中进行查询,但是实际操作中禁止在主线程操作数据库,避免出现ANR问题。需要开启子线程进行数据的操作!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class RoomActivity extends AppCompatActivity {
private StudentDataBase studentDataBase;
private StudentDao studentDao;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_room);
studentDataBase = Room.databaseBuilder(
getApplicationContext(),
StudentDataBase.class,
"StudentDao"
).build();
studentDao = studentDataBase.studentDao();
}

private int defaultClick=1;
public void addData(View view) {
new Thread(new Runnable() {
@Override
public void run() {
StudentEntity studentEntity = new StudentEntity();
studentEntity.setName("name:"+defaultClick);
studentEntity.setAge(defaultClick);
studentEntity.setPwd("pwd:"+defaultClick);
long l = studentDao.insertStudent(studentEntity);
defaultClick++;
if (l!=0){
Log.e("tyl","添加成功");
}else {
Log.e("tyl","添加失败");
}
}
}).start();
}

public void deleteData(View view) {
new Thread(new Runnable() {
@Override
public void run() {
List<StudentEntity> allStudentList = studentDao.getAllStudentList();
if (allStudentList!=null&&allStudentList.size()!=0){
studentDao.deletePerson(allStudentList.get(allStudentList.size()-1));
}
}
}).start();
}

public void changeData(View view) {
new Thread(new Runnable() {
@Override
public void run() {
List<StudentEntity> allStudentList = studentDao.getAllStudentList();
if (allStudentList!=null&&allStudentList.size()!=0){
StudentEntity studentEntity = allStudentList.get(allStudentList.size() - 1);
studentEntity.setName("upData");
studentEntity.setAge(0);
studentDao.updatePerson(studentEntity);
}
}
}).start();
}

public void queryData(View view) {
new Thread(new Runnable() {
@Override
public void run() {
List<StudentEntity> allStudentList = studentDao.getAllStudentList();
if (allStudentList!=null&&allStudentList.size()!=0){
for (int i = 0; i <allStudentList.size() ; i++) {
StudentEntity studentEntity = allStudentList.get(i);
Log.e("tyl","id:"+studentEntity.getId());
Log.e("tyl","name:"+studentEntity.getName());
Log.e("tyl","pwd:"+studentEntity.getPwd());
Log.e("tyl","age:"+studentEntity.getAge());
}
}
}
}).start();
}
}