ROOM
Room 是一个数据库对象映射库,可以轻松访问 Android 应用程序上的数据库。
Room 没有隐藏 SQLite 的细节,而是试图通过提供方便的 API 来查询数据库并在编译时验证此类查询来包含它们。这允许您访问 SQLite 的全部功能,同时拥有 Java SQL 查询构建器提供的类型安全。
Room 不需要因为操作数据库而学习其他方法,相比其他库更好上手。还可以在 Android Studio 的 Database Inspector 中管理数据库。
三个重要组件:
- Database:数据库
- Entity:数据库中的表
- Dao:操作表中数据的方法
声明依赖
没有相应的 optional 可以不添加
dependencies {
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// optional - Paging 3 Integration
implementation "androidx.room:room-paging:2.4.0-alpha04"
}
简单使用
一个表的增删改查
创建数据库
@Database:数据库,entities:属于该数据库的所有表,version:版本,exportSchema:生成数据库创建表或升级等操作及字段描述的 json 文件,默认为 true,这里写 false 是防止报错。
Room.databaseBuilder():数据库生成器。上下文,类,数据库名称。
allowMainThreadQueries():禁用 Room 的主线程查询检查。
@Database(entities = {User.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase myDb;
public static MyDatabase getInstance(Context context) {
if (myDb == null) {
myDb = Room.databaseBuilder(context, MyDatabase.class, "users.db")
.allowMainThreadQueries()
.build();
}
return myDb;
}
}
创建表
@Entity:表,tableName:表的名称,可以不加。
@PrimaryKey:主键,autoGenerate:是否自增。构造函数中可以没有 userId,添加记录时自增。
@ColumnInfo:列(字段),name:列名称(字段名)。
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
long userId;
@ColumnInfo(name = "user_name")
String userName;
@ColumnInfo(name = "user_phone")
String userPhone;
@ColumnInfo(name = "user_gender")
String gender;
public User(String userName, String userPhone, String gender) {
this.userName = userName;
this.userPhone = userPhone;
this.gender = gender;
}
// 省略 Getter 和 Setter
// 一定要有,只是我这里省略
}
接口中创建操作表需要使用的方法
@Query:查询,用到的语句都是 SQLite 语句,FROM 后的表名是 tableName,如果没有设置 tableName,则使用类名。第二条查询语句:查询输入的 userId 根据表中 userId 字段下的数据查询。
@Insert:增,示例中有两种添加方法,第一种添加单个数据,第二种添加多个数据(集合或数组)。
@Delete:删,可以是集合或数组。
@Update:改,可以是集合或数组。
@Dao
public interface UserDao {
@Query("SELECT * FROM users")
List<User> getAll();
@Query("SELECT * FROM users WHERE userId=:userId")
User getUser(long userId);
@Insert
void add(User user);
@Insert
void addAll(User... users);
@Delete
void remove(User user);
@Update
void update(User user);
}
在 Database 中添加 Dao
public abstract UserDao userDao();
使用
User userInfo = new User(userName, userPhone, gender);
MyDatabase.getInstance(this).userDao().add(userInfo); // 插入数据
List<User> list = MyDatabase.getInstance(this).userDao().getAll(); // 获取表中所有数据
多表关联
使用外键让两个表有关联
创建表
@ForeignKey:外键,entity:父表,parentColumns:父表中相关联字段,childColumns:子表中与之相关联字段。
@Index:索引,value:索引或者组合索引包含的列,unique:设置唯一约束。
@Entity(tableName = "score", foreignKeys = @ForeignKey(entity = User.class, parentColumns = "userId", childColumns = "emp_id"),
indices = @Index(value = {"emp_id"}, unique = true))
public class Score {
@PrimaryKey(autoGenerate = true)
long id;
@ColumnInfo(name = "emp_id")
long empId;
@ColumnInfo(name = "math")
int math;
@ColumnInfo(name = "language")
int language;
public Score(long empId, int math, int language) {
this.empId = empId;
this.math = math;
this.language = language;
}
// 同样省略了 Getter 和 Setter
}
接口中创建操作表需要使用的方法
Info 是为了放数据的另一个表,写的很潦草,没有主键,四个字段(emp_id, user_name, math, language)。
@Query:第一条:在 users 中查询 users.userId = score.emp_id 的数据,只显示数据的 emp_id,user_name,math,language 信息;第二条:根据输入 id 查询某条记录,我这里用于更新。
@Insert:增。
@Update:根据查找到的某条记录修改。
@Dao
public interface ScoreDao {
@Query("SELECT emp_id,user_name,math,language from users INNER JOIN score ON users.userId=score.emp_id")
List<Info> getInfo();
@Query("SELECT * FROM score WHERE emp_id=:id")
Score getInfo(long id);
@Insert
void add(Score score);
@Update
void update(Score score);
}