Room 数据库简单使用
一、说明
Room是一个SQLite抽象层,使用更加简单,通过注解的方式标记相关功能,编译时自动生成响应的 impl 实现类,具有丰富的编译时校验,错误提示。
类注解:
- @Entity:映射为数据库中的一张表。
- @Dao:即 Data Access Objects,数据访问对象。
- @Database:数据库,标注的类必须是抽象类,在注解中添加与数据库关联的表,包含使用 @Dao 注解标记的类的抽象方法。
类内注解:
- @PrimaryKey():标识主键。
- @NonNull:字段非空标识。
- @ColumnInfo(“XXX”):字段名。
- @Insert():插入方法。
- @Query():查询方法。
- @Delete:删除方法。
- @Ignore:忽视该方法或字段。
测试过程中错误点:
1、主键需要使用 @NonNull 标注。
2、tablename 必须和实体类名称相同,大小写也要一模一样。
3、@Database 中加入 exportSchema = false。
4、@Insert 注解方法的返回值是 Long,插入多个则是 List。
5、@Query() 可以用于执行 SQL 语句,参数引用方法为“:参数名 ”,“:”不能去。
6、Entity 实体类定义中,构造函数只能显式一个,其余不显式的使用 @Ignore 标注。
7、如果定义了列值唯一,主键自带唯一。当插入的数据该列在数据库中已经存在,则会报异常SQLiteConstraintException,try/catch 打个数据已存在的 Log 即可。
8、数据操作开子线程去拿,不然也会报错。
二、使用
- 添加依赖
在官网找合适版本的依赖。(Room 依赖极易出错,请小心)加在 build 的 dependencies 下。
测试使用依赖为:
implementation "androidx.room:room-common:2.4.3"
annotationProcessor "androidx.room:room-compiler:2.4.3"
implementation "androidx.room:room-runtime:2.4.3"
- 使用注解自定义实体类
@Entity(tableName = "Fruit")
public class Fruit {
@PrimaryKey
@NonNull
public Integer id;
@ColumnInfo(name = "fruit_name")
public String fruitName;
@ColumnInfo(name = "fruit_type")
public String fruitType;
@ColumnInfo(name = "fruit_price")
public Integer fruitPrice;
@ColumnInfo(name = "fruit_num")
public Integer fruitNum;
@Ignore
public Fruit(Integer id, String fruitName, String fruitType, Integer fruitPrice, Integer fruitNum) {
this.id = id;
this.fruitName = fruitName;
this.fruitType = fruitType;
this.fruitPrice = fruitPrice;
this.fruitNum = fruitNum;
}
public Fruit() {
}
@NonNull
public Integer getId() {
return id;
}
public void setId(@NonNull Integer id) {
this.id = id;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitType() {
return fruitType;
}
public void setFruitType(String fruitType) {
this.fruitType = fruitType;
}
public Integer getFruitPrice() {
return fruitPrice;
}
public void setFruitPrice(Integer fruitPrice) {
this.fruitPrice = fruitPrice;
}
public Integer getFruitNum() {
return fruitNum;
}
public void setFruitNum(Integer fruitNum) {
this.fruitNum = fruitNum;
}
@Override
public String toString() {
return "Fruit{" +
"id=" + id +
", fruitName='" + fruitName + '\'' +
", fruitType='" + fruitType + '\'' +
", fruitPrice=" + fruitPrice +
", fruitNum=" + fruitNum +
'}';
}
}
- 自定义 Dao 接口
@Dao
public interface MyDAO {
/**参数可为List**/
//返回插入的 rowId 值,long 型
@Insert
Long insertFruit(Fruit fruit);
//插入列表
@Insert
List<Long> insertList(List<Fruit> list);
//返回受影响的行数
@Delete
int deleteFruit(Fruit fruit);
//返回受影响的行数
@Update(entity = Fruit.class)
int updateFruit(Fruit fruit);
//返回查询的数据
@Query("select * from fruit;")
List<Fruit> selectAllFruit();
}
- 自定义 Database 抽象类
@Database(version = 1,entities = {Fruit.class},exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {
public abstract MyDAO myDAO();
}
- 测试,需要 context
new Thread(() -> {
MyDatabase database = Room.databaseBuilder(getApplicationContext(), MyDatabase.class, "Fruit").build();
MyDAO dao = database.myDAO();
try {
//插入单个
dansertFruit(new Fruit(1, "橘子", "橘子", 10, 120));
//插入 List
List<Fruit> entityList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Fruit entity = new Fruit(i, "" + i, "" + i, i, i);
entityList.add(entity);
}
dao.insertList(entityList);
} catch (SQLiteConstraintException e) {
//id 为 1 那一项会导致异常,因为数据库已经存在该主键数据
Log.e(TAG, "There are same data in local!!!");
}
Log.d(TAG, "insert success,size:");
//查找 Fruit
List<Fruit> fruits = dao.selectAllFruit();
Fruit fruit = new Fruit();
if (fruits.size() > 0) {
fruit = fruits.get(0);
}
Log.d(TAG, "初始数据库中Fruit为:" + fruit);
//修改 Fruit
fruit.setFruitName("苹果");
fuit.setFruitType("苹果");
dao.updateFruit(fruit);
//查找 Fruit
List<Fruit> fruitList = dao.selectAllFruit();
Fruit f = new Fruit();
if (fruits.size() > 0) {
fruit = fruits.get(0);
}
Log.i(TAG, "修改后的数据 Fruit 为:" + f);
//删除 Fruit
dao.deleteFruit(f);
//查找 Fruit
List<Fruit> list = dao.selectAllFruit();
Fruit fi = new Fruit();
if (fruits.size() > 0) {
fruit = fruits.get(0);
}
Log.d(TAG, "删除后数据库中Fruit为:" + fi);
}).start();