Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。具体来说,Room 具有以下优势:
- 针对 SQL 查询的编译时验证。
- 可最大限度减少重复和容易出错的样板代码的方便注解。
- 简化了数据库迁移路径。
出于这些方面的考虑,我们强烈建议您使用 Room,而不是直接使用 SQLite API。
Room 包含三个主要组件:
dependencies {
// Room
implementation "androidx.room:room-runtime:2.2.5"
annotationProcessor "androidx.room:room-compiler:2.2.5"
}
1.创建User类
public class User {
public int id;
public int age;
public String name;
public String phone;
}
2.添加注解
- 默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。
- 同样,Room 默认使用字段名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 @ColumnInfo 注解添加到该字段并设置 name 属性。
- 每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行。执行此操作的最直接方式是使用 @PrimaryKey 为单个列添加注解(注意:如果您需要 Room 为实体实例分配自动 ID,请将 @PrimaryKey 的 autoGenerate 属性设为 true。)
- 默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果某个实体中有您不想保留的字段,则可以使用 @Ignore 为这些字段添加注解,
当您使用 Room 持久性库存储应用的数据时,您可以通过定义数据访问对象 (DAO) 与存储的数据进行交互。每个 DAO 都包含一些方法,这些方法提供对应用数据库的抽象访问权限。在编译时,Room 会自动为您定义的 DAO 生成实现。
通过使用 DAO(而不是查询构建器或直接查询)来访问应用的数据库,您可以使关注点保持分离,这是一项关键的架构原则。DAO 还可让您在测试应用时更轻松地模拟数据库访问。
您可以将每个 DAO 定义为一个接口或一个抽象类。对于基本用例,您通常应使用接口。无论是哪种情况,您都必须始终使用 @Dao 为您的 DAO 添加注解。DAO 不具有属性,但它们定义了一个或多个方法,可用于与应用数据库中的数据进行交互。
以下代码是一个简单 DAO 的示例,它定义了在 Room 数据库中插入、删除和选择 User 对象的方法:
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
@Dao
public interface UserDao {
@Insert
void insertAll(User user);
@Delete
void delete(User user);
@Query("SELECT * FROM users")
List getAll();
}
以下代码定义了用于保存数据库的 AppDatabase 类。 AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。数据库类必须满足以下条件:
- 该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
- 该类必须是一个抽象类,用于扩展 RoomDatabase。
- 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = User.class,version = 1)
public abstract class UserDatabase extends RoomDatabase {
public abstract UserDao getUserDao();
}
Database的初始化需要先使用Room.databaseBuilder方法,这个方法几个参数:
AppDatabase db = Room.databaseBuilder(getApplicationContext(),
AppDatabase.class, "database-name").build();
Room.databaseBuilder方法生成的RoomDatabase.Builder对象调用build方法就生成了AppDatabase对象
然后,您可以使用 AppDatabase 中的抽象方法获取 DAO 的实例,转而可以使用 DAO 实例中的方法与数据库进行交互:
UserDao userDao = db.userDao();
List users = userDao.getAll();
1.在Dao层写增加的方法
以下代码展示了将一个或多个 User 对象插入数据库的有效 @Insert 方法示例:
@Dao
public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertUsers(User... users);
@Insert
public void insertBothUsers(User user1, User user2);
@Insert
public void insertUsersAndFriends(User user, List friends);
}
@Insert 方法的每个参数必须是带有 @Entity 注解的 Room 数据实体类的实例或数据实体类实例的集合。调用 @Insert 方法时,Room 会将每个传递的实体实例插入到相应的数据库表中。
如果 @Insert 方法接收单个参数,则会返回 long 值,这是插入项的新 rowId。如果参数是数组或集合,则该方法应改为返回由 long 值组成的数组或集合,并且每个值都作为其中一个插入项的 rowId。
2.在main方法中调用
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
User user=new User();
user.name="小冯";
user.age=20;
user.phone="123456789";
userDao.insertAll(user);
}
});
运行结果:
1.在Dao层中写删除方法
借助 @Delete 注释,您可以定义从数据库表中删除特定行的方法。与 @Insert 方法类似,@Delete 方法接受数据实体实例作为参数。 以下代码展示了一个 @Delete 方法示例,尝试从数据库中删除一个或多个 User 对象:
@Dao
public interface UserDao {
@Delete
public void deleteUsers(User... users);
}
2.在main方法中调用
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
User user=new User();
user.id=1;
userDao.delete(user);
}
});
运行结果:
1.在Dao层中写更新方法
借助 @Update 注释,您可以定义更新数据库表中特定行的方法。与 @Insert 方法类似,@Update 方法接受数据实体实例作为参数。 以下代码展示了一个 @Update 方法示例,该方法尝试更新数据库中的一个或多个 User 对象:
@Dao
public interface UserDao {
@Update
public void updateUsers(User... users);
}
Room 使用主键将传递的实体实例与数据库中的行进行匹配。如果没有具有相同主键的行,Room 不会进行任何更改。
@Update 方法可以选择性地返回 int 值,该值指示成功更新的行数。
2.在main方法中调用
findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
User user=new User();
user.id=4;
user.name="xiao冯";
user.age=22;
user.phone="1111111";
userDao.update(user);
}
});
运行结果:
1.在Dao层中写查询方法
使用 @Query 注解,您可以编写 SQL 语句并将其作为 DAO 方法公开。使用这些查询方法从应用的数据库查询数据,或者需要执行更复杂的插入、更新和删除操作。
Room 会在编译时验证 SQL 查询。这意味着,如果查询出现问题,则会出现编译错误,而不是运行时失败。
@Query("SELECT * FROM user")
public User[] loadAllUsers();
2.在main方法中调用
findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List userList=userDao.findAllUser();
for (User user:userList){
Log.i("Usertag","id: "+user.id+" name:"+user.name+" 电话号:"+user.phone);
}
}
});
运行结果:
1.增加布局控件
2.增加Dao层方法
@Query("SELECT * FROM users where id= :userId")
List findUserById(int userId);
3.在main方法中调用
EditText editText=findViewById(R.id.editTextTextPersonName);
findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List userList=userDao.findUserById(Integer.parseInt(String.valueOf(editText.getText())));
for (User user:userList){
Log.i("Usertag","id: "+user.id+" name:"+user.name+" 电话号:"+user.phone);
}
}
});
运行结果: