Android数据库操作之:Room的引⼊及使⽤(整理)
⼀、简单说明
1、官⽅推荐
Room 在 SQLite 上提供了⼀个抽象层,以便在充分利⽤ SQLite 的强⼤功能的同时,能够流畅地访问数据库。⾕歌强烈建议使⽤ Room ⽽不是 SQLite。
2、主要内容点
Room 包含 3 个主要组件:
(1)数据库:包含数据库持有者,并作为应⽤已保留的持久关系型数据的底层连接的主要接⼊点。
使⽤ @Database 注释的类应满⾜以下条件:
是扩展 RoomDatabase 的抽象类。
在注释中添加与数据库关联的实体列表。
包含具有 0 个参数且返回使⽤ @Dao 注释的类的抽象⽅法。
在运⾏时,您可以通过调⽤ Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取 Database 的实例。
(2)Entity:表⽰数据库中的表。
(3)DAO:包含⽤于访问数据库的⽅法。
应⽤使⽤ Room 数据库来获取与该数据库关联的数据访问对象 (DAO)。然后,应⽤使⽤每个 DAO 从数据库中获取实体,然后再将对这些实体的所有更改保存回数据库中。 最后,应⽤使⽤实体来获取和设置与数据库中的表列相对应的值。
3、引⼊
android {
defaultConfig {
......
javaCompileOptions {
抽象类的使用
annotationProcessorOptions {
arguments +=[
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true",
"pandProjection":"true"]
/*
Room 具有以下注释处理器选项:
room.schemaLocation:配置并启⽤将数据库架构导出到给定⽬录中的 JSON ⽂件的功能。
[创建好表和数据库后编译,会在 app/schemas ⽬录下⽣成这个 JSON ⽂件]
room.incremental:启⽤ Gradle 增量注释处理器。
*/
}
}
}
}
dependencies {
......
// room
def room_version ="2.2.5"
implementation ":room-runtime:$room_version"
annotationProcessor ":room-compiler:$room_version"
/
/ For Kotlin use kapt instead of annotationProcessor
// 对于Kotlin来说,使⽤kapt⽽不是annotationProcessor
// kapt ":room-compiler:$room_version"
}
⼆、基本使⽤
1、RoomDatabase
t.Context;
Database;
Room;
RoomDatabase;
@Database(entities ={User.class}, version =1)
public abstract class AppDatabase extends RoomDatabase {
private static volatile AppDatabase mAppDatabase;
// TODO 在实例化 AppDatabase 对象时应遵循单例设计模式。每个 RoomDatabase 实例的成本相当⾼,⼏乎不需要在单个进程中访问多个实例。static AppDatabase getInstance(Context context){
if(mAppDatabase == null){
synchronized(AppDatabase.class){
if(mAppDatabase == null){
mAppDatabase = Room.ApplicationContext(), AppDatabase.class,"dbRoomTest.db")
.addMigrations()
// 默认不允许在主线程中连接数据库
// .allowMainThreadQueries()
.build();
}
}
}
return mAppDatabase;
}
public abstract UserDao userDao();
}
2、Dao
Dao;
Delete;
Insert;
Query;
Update;
import java.util.List;
// TODO Dao 必须是接⼝或者抽象类,Room 使⽤注解⾃动⽣成访问数据库的代码
@Dao
public interface UserDao {
@Insert
void insertUser(User users);
// TODO 如果插⼊的数据在数据库表中已经存在,就会抛出异常
@Insert
void insertUsers(List<User> users);
@Insert
void users);
// 如果 @Insert ⽅法只接收 1 个参数,则它可以返回 long,这是插⼊项的新 rowId。如果参数是数组或集合,则应返回 long[] 或 List<Long>。
@Delete
void delete(User user);
// TODO 如果通过 Entity 来删除数据,传进来的参数需要包含主键
@Delete
void users);
// 虽然通常没有必要,但是您可以让此⽅法返回⼀个 int 值,以指⽰从数据库中删除的⾏数。
@Update
void updateUser(User users);
// TODO 如果通过 Entity 来更新数据,传进来的参数需要包含主键,参数会覆盖旧数据,参数中没有值的字段将置为 null
// TODO 如果通过 Entity 来更新数据,传进来的参数需要包含主键,参数会覆盖旧数据,参数中没有值的字段将置为 null
@Update
void users);
// 虽然通常没有必要,但是您可以让此⽅法返回⼀个 int 值,以指⽰数据库中更新的⾏数
/*
@Query 是 DAO 类中使⽤的主要注释。它允许您对数据库执⾏读/写操作。
每个 @Query ⽅法都会在编译时进⾏验证,因此如果查询出现问题,则会发⽣编译错误,⽽不是运⾏时失败。
Room 还会验证查询的返回值,以确保当返回的对象中的字段名称与查询响应中的对应列名称不匹配时,Room 可以通过以下两种⽅式之⼀提醒您:
1、如果只有部分字段名称匹配,则会发出警告。
2、如果没有任何字段名称匹配,则会发出错误。
*/
@Query("SELECT * FROM users")
List<User>loadAll();
@Query("SELECT * FROM users WHERE uid=(:userId)")
User findUserById(int userId);
@Query("SELECT * FROM users WHERE uid IN (:userIds)")
List<User>loadAllByIds(int[] userIds);
@Query("SELECT * FROM users WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1")
User findUserByName(String first, String last);
@Query("SELECT * FROM users WHERE first_name LIKE :first AND last_name LIKE :last")
List<User>loadAllByName(String first, String last);
/*
返回列的⼦集:
⼤多数情况下,您只需获取实体的⼏个字段。
例如,您的界⾯可能仅显⽰⽤户的名字和姓⽒,⽽不是⽤户的每⼀条详细信息。
通过仅提取应⽤界⾯中显⽰的列,您可以节省宝贵的资源,并且您的查询也能更快完成。
借助 Room,您可以从查询中返回任何基于 Java 的对象,前提是结果列集合会映射到返回的对象。
例如,您可以创建以下基于 Java 的普通对象 (POJO) 来获取⽤户的名字和姓⽒。
Room 知道该查询会返回 first_name 和 last_name 列的值,并且这些值会映射到 NameTuple 类的字段中。因此,Room 可以⽣成正确的代码。
如果查询返回的列过多,或者返回 NameTuple 类中不存在的列,则 Room 会显⽰⼀条警告。
*/
@Query("SELECT first_name, last_name FROM users")
List<NameTuple>loadFullName();
}
列的⼦集
ColumnInfo;
public class NameTuple {
@ColumnInfo(name ="first_name")
public String firstName;
@ColumnInfo(name ="last_name")
public String lastName;
}
3、Entity
ColumnInfo;
Embedded;
Entity;
Ignore;
PrimaryKey;
// 默认情况下,Room 将类名称⽤作数据库表名称
// 如果希望表具有不同的名称,请设置 @Entity 注释的 tableName 属性【个⼈建议】@Entity(tableName ="users")
public class User {
// 主键
@PrimaryKey(autoGenerate =true)
@ColumnInfo(name ="uid")
public int uid;
// 与 tableName 属性类似,Room 将字段名称⽤作数据库中的列名称
// 如果希望列具有不同的名称,请将 @ColumnInfo 注释添加到字段【个⼈建议】
@ColumnInfo(name ="first_name")
public String firstName;
@ColumnInfo(name ="last_name")
public String lastName;
// 默认情况下,Room 会为实体中定义的每个字段创建⼀个列
/
/ 如果某个实体中有不想保留的字段,则可以使⽤ @Ignore 为这些字段添加注释
@Ignore
Bitmap picture;
// 嵌套对象
@Embedded
public Address address;
}
嵌套对象
ColumnInfo;
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name ="post_code")
public int postCode;
}
三、其他
1、事务
(1) 如果要批量重复操作怎么办?
Room ⾃动⽣成的 Dao 实现类会对批量操作添加事务控制:
(2) 如果要批量不重复操作怎么办?
下⾯⽤重复的插⼊操作来模拟,实际中可以采⽤复杂的操作组合:RoomDatabase#runInTransaction(java.lang.Runnable)
final ArrayList<User> users =new ArrayList<>();
for(int i =0; i <10000; i++){
User user =new User();
user.firstName ="No"+ i;
user.lastName ="number"+ i;
users.add(user);
}
final AppDatabase db = Instance(this);
db.runInTransaction(new Runnable(){
@Override
public void run(){
for(User user : users){
db.userDao().insertUser(user);
}
}
});
99、复杂⽤法
根据项⽬需要,如果涉及到复杂的功能实现,可以参考官⽅⽂档:
参考⽂章:
1、《》
2、《》

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。