Room
Room是什么
- Room是Goole推出的数据库框架,属于ORM库。
ORM(ObjectRelational Mapping)也叫对象关系映射。简单来讲,我们使用的编程语言是面向对象语言,而使用的数据库则是关系型数据库,将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是ORM了。 - Room是一个持久性数据库。
Room持久性库提供了SQLite的抽象层,以便在充分利用SQLite的同时允许流畅的数据库访问,利用SQlite的全部功能。
- 优点
- SQL查询在编译时就会验证 - 在编译时检查每个@Query和@Entity等,这就意味着没有任何运行时错误的风险可能会导致应用程序崩溃(并且它不仅检查语法问题,还会检查是否有该表)
- 较少的模板代码
- 与 LiveData集成
- 与Rxjava结合可以实时监听数据变化
Room组件
- Entity:数据实体,对应数据库中的表
- DAO:数据访问对象,提供用于查询、更新、插入和删除数据库中的数据的方法。
- Database:用于保存数据库并作为应用持久性数据底层连接的主要访问点。
Room架构图
实现流程
首先实现一个实例,有一个大概的了解,其次分模块学习。
- 数据实体(Entity)
定义了一个 User 数据实体。User 的每个实例都代表应用数据库中 user 表中的一行。
@Entity
public class User {
@PrimaryKey
public int uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
- 数据访问对象 (DAO)
定义了一个名为 UserDao 的 DAO。UserDao 提供了应用的其余部分用于与 user 表中的数据交互的方法。
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
-
数据库(Database)
数据库类必须满足以下条件:
- 该类必须带有
@Database
注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。 - 该类必须是一个抽象类,用于扩展
RoomDatabase
。 - 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参
- 该类必须带有
以下代码定义了用于保存数据库的 AppDatabase
类。 AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。
数的抽象方法,并返回 DAO 类的实例。
@Database(entities = {
User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
- 用法
定义数据实体、DAO 和数据库对象后,创建数据库实例:
AppDatabase db = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "database-name").build();
//使用 AppDatabase 中的抽象方法获取 DAO 的实例
//使用 DAO 实例中的方法与数据库进行交互
UserDao userDao = db.userDao();
List<User> users = userDao.getAll();
使用 Room 实体定义数据
实体详解
- 您可以将每个 Room 实体定义为带有
@Entity
注解的类。Room 实体包含数据库中相应表中的每一列的字段,包括构成主键的一个或多个列。
以下代码是一个简单实体的示例,定义了一个 User 表,其中包含 ID 列、名字列和姓氏列:
@Entity
public class User {
@PrimaryKey
public int uid;
public String firstName;
public String lastName;
}
注意:要保留某个字段,Room 必须拥有该字段的访问权限。您可以通过将某个字段设为公开或为其提供 getter 和 setter 方法,确保 Room 能够访问该字段。
默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity
注解的 tableName 属性。同样,Room 默认使用字段名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 @ColumnInfo
注解添加到该字段并设置 name 属性。
//使用Entity注解的tableName属性:更改数据库表的名称
@Entity(tableName = "users")
public class User {
@PrimaryKey
public int id;
//使用ColumnInfo提供的name属性:更改数据库中的列名称
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
//实现getter,setter方法
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
注意:SQLite中的表和列都不区分大小写。
定义主键
每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行。执行此操作的最直接方式是使用 @PrimaryKey
为单个列添加注解:
@NonNull //主键不能为空,必须添加该注解
@PrimaryKey(autoGenerate = false)//设置为true,让SQlite生成唯一的ID(即添加一个主键)
public int id;
注意:如果您需要 Room 为实体实例分配自动 ID,请将 @PrimaryKey
的 autoGenerate 属性设为 true。
定义复合主键
通过列出 @Entity
的 primaryKeys 属性中的以下列定义一个复合主键:
@Entity(primaryKeys = {
"firstName", "lastName"})
public class User {
public String firstName;
public String lastName;
}
忽略字段
默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果某个实体中有不想保留的字段,则可以使用 @Ignore
为这些字段添加注解。
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
public String Name;
//该字段将被忽略
使用 Room DAO 访问数据
当您使用 Room 持久性库存储应用的数据时,您可以通过定义数据访问对象 (DAO) 与存储的数据进行交互。每个 DAO 都包含一些方法,这些方法提供对应用数据库的抽象访问权限。在编译时,Room 会自动为您定义的 DAO 生成实现。
将每个 DAO 定义为一个接口或一个抽象类,但通常应使用接口。无论是哪种情况,都必须始终使用 @Dao
添加注解。DAO 不具有属性,但它们定义了一个或多个方法,可用于与应用数据库中的数据进行交互。
有两种类型的 DAO 方法可以定义数据库交互:
- 不编写任何 SQL 代码的情况下插入、更新和删除数据库中行的便捷方法。
- 编写自己的 SQL 查询以与数据库进行交互的查询方法。
不编写SQL 代码的便捷方法
- 插入
借助@Insert
注释,将其参数插入到数据库中的相应表中的方法。
a.@Insert
方法的每个参数必须是带有@Entity
注解实体类的实例或数据实体类的集合。
b. 调用方法时,Room 会将每个传递的实体实例插入到相应的数据库表中。
c. 如果@Insert
方法接收单个参数,则会返回long
值,这是插入项的新rowId
。
d. 如果参数是数组或集合,则该方法应改为返回由long
值组成的数组或集合,并且每个值都作为其中一个插入项的rowId
。
@Dao
public interface UserDao {
//实现一个或多个User对象插入数据库
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertUsers(User... users);
@Insert
public void insertBothUsers(User user1, User user2);
@Insert
public void insertUsersAndFriends(User user, List<User> friends);
}
- 更新/删除
借助@Update
/@Delete
注释,定义更新数据库表中特定行的方法。
a. Room 使用主键将传递的实体实例与数据库中的行进行匹配。如果没有具有相同主键的行, Room 不会进行任何更改。
b.@Update
/@Delete
方法可以选择性的返回 int 值,该值指示成功更新的行数。
@Dao
public interface UserDao {
//更新
@Update
public void updateUsers(User... users);
//删除
@Delete
public void deleteUsers(User... users);
}
编写 SQL 代码的查询方法
使用 @Query
注解,您可以编写 SQL 语句并将其作为 DAO 方法公开。使用这些查询方法从应用的数据库查询数据,或者需要执行更复杂的插入、更新和删除操作。
Room 会在编译时验证 SQL 查询。这意味着,如果查询出现问题,则会出现编译错误,而不是运行时失败。
- 使用Room写SQL引用查询条件的格式是“字段名称=:引用值”
//使用简单的 SELECT 查询返回数据库中的所有 User 对象:
//SQLite中的表和列都不区分大小写。
@Query("SELECT * FROM user")
public User[] loadAllUsers();
//查询指定first_name的数据
@Query("SELECT * FROM user where first_name =: name")
public User loadUsers_first();
//查询指定last_name的数据
@Query("SELECT * FROM user where last_name =: name")
public User loadUsers_last();
//删除所有 User 对象:
@Query("DELETE * FROM user")
public void deleteAllUsers();
//删除指定first_name的数据
@Query("DELETE * FROM user where first_name =: name")
public void loadUsers_first();
demo地址
https://github.com/Mike-Shake/Demo_zujian/tree/master/room_demo2