(1)Room是jetpack的组件之一,是一个独立的数据库 ,是对sqlite(是用sql c 语言实现,使用比较复杂)数据库的封装,使用比较简单。
(2)可以结合liveDate lifecycle 使用
(3)使用APT注解处理器生成代码完成
(4)Room的三大角色:用户操作时只针对Dao进行操作即可,是Room设计的初衷
数据类(class student 一张表)@Entity 操作(增删改查StudentDao)@Dao 数据库()@DataBase(v = 3)数据库版本号为3
一、AS中安装database 插件
1、File->Settings->Plugins 中MarketPlace中搜索database 找到"Database Navigator" 点击安装,安装完成后点击重启AS按钮;
2、重启后,AS 界面左侧出现“DB Browser”,则插件安装完毕。
二、Room的使用(Java)
1、在app的build.gradle中添加包
// 下面是 ROOM依赖相关的代码
def room_version = "2.0.0-beta01"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
2、新建表(用@Entity修饰)
注意:表中需要包含主键,且自增长;
// Student.java
package com.test.databindingtestjava.room.entity;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
/**
* @ClassName Student
* @Description TODO
* @Author lili
* @DATE 2022/11/5 14:19
*/
@Entity
public class Student {
@PrimaryKey(autoGenerate = true) // PrimaryKey 主键;autoGenerate自增长
private int uid;
//下面定义表中包含的列(字段)
@ColumnInfo(name="name") // ColumnInfo 列信息
private String name;
@ColumnInfo(name="age")
private int age;
@ColumnInfo(name="address")
private String address;
@ColumnInfo(name="number")
private String number;
//构造函数
public Student() {}
public Student(int uid,String name, int age, String address, String number) {
this.uid = uid;
this.name = name;
this.age = age;
this.address = address;
this.number = number;
}
public Student(String name, int age, String address, String number) {
this.name = name;
this.age = age;
this.address = address;
this.number = number;
}
//外部调用方法
public void setUid(int uid) {
this.uid = uid;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public void setNumber(String number) {
this.number = number;
}
public int getUid() {
return uid;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
public String getNumber() {
return number;
}
@Override
public String toString() {
return "Student{" +
"uid=" + uid +
", name='" + name + '\'' +
", age='" + age + '\'' +
", address=" + address + '\'' +
", number = " + number + '\'' +
'}';
}
}
2、新建Dao接口(用@Dao修饰)
添加增 删 改 查 接口
// StudentDao.java 接口
package com.test.databindingtestjava.room.dao;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import com.test.databindingtestjava.room.entity.Student;
import java.util.List;
@Dao
public interface StudentDao {
// 增
@Insert
void insert(Student...students);
// 删
@Delete
void delete(Student student);
// 改
@Update
void update(Student student);
//查(所有)
@Query("select * from Student")
List<Student> getAll();
//查(按姓名name查)
@Query("select * from Student where name like :name ")
Student getByName(String name);
//查(按主键id查)
@Query("select * from Student where id in(:ids)")
List<Student> getById(int[] ids);
}
3、新建数据库(@Database(entities = {Student.class},version = 1,exportSchema = false))
由于 Room使用APT注解处理器 技术,会自动生成数据库实现代码,因此,该方法为抽象类。
//StudentDB.class
package com.test.databindingtestjava.room.db;
import androidx.room.Database;
import androidx.room.RoomDatabase;
import com.test.databindingtestjava.room.dao.StudentDao;
import com.test.databindingtestjava.room.entity.Student;
/**
* @ClassName StudentDB
* @Description TODO
* @Author lili
* @DATE 2022/11/5 15:01
*/
// entities = Student.class: 该数据库包含的表
// version = 1: 该数据库版本
// exportSchema = false : 尽量写,内部需要检测,如果没有写,会抛出异常,因为内部要记录升级的所有副本
@Database(entities = {Student.class},version = 1,exportSchema = false)
public abstract class TestDB extends RoomDatabase {
// 暴露Dao
public abstract StudentDao getDao();
}
4、使用Dao,完成数据库的增 删 改 查
//MainActivity.class
package com.test.databindingtestjava;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.room.Room;
import com.test.databindingtestjava.databinding.ActivityMaintestBinding;
import com.test.databindingtestjava.room.dao.StudentDao;
import com.test.databindingtestjava.room.db.TestDB;
import com.test.databindingtestjava.room.entity.Student;
import java.util.List;
/**
* @ClassName MainActivityTest
* @Description TODO
* @Author lili
* @DATE 2022/11/2 13:46
*/
public class MainActivityTest extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testThread thread = new testThread();
thread.start();
}
public class testThread extends Thread{
@Override
public void run() {
super.run();
// 创建数据库
TestDB testDB = Room.databaseBuilder(getApplicationContext()
,TestDB.class
,"testDB")
//可以设置强制主线程,默认是让你用子线程
// .allowMainThreadQueries()
.build();
// 获取Dao
StudentDao dao = testDB.getDao();
//增
dao.insert(new Student("lily",20,"hrb","123456789")
,new Student("liyu",24,"hrbcs","977336373")
,new Student("yuh",26,"hrbdal","35363647474")
,new Student("ddhfff",23,"hrbwuc","63736374848")
,new Student("ffjdfjf",50,"hrbshuanc","12345645")
,new Student("黄飞鸿",98,"哈尔滨","0987654"));
//获取所有
List<Student> all = dao.getAll();
Log.d("testRoom","测试新增数据:" + all.toString());
//更新数据
dao.update(new Student(3,"合法",98,"黑龙江","0987654"));
List<Student> updateAll = dao.getAll();
Log.d("testRoom","测试更新数据:" + updateAll.toString());
// 查询
Student student = dao.getByName("黄飞鸿");
Log.d("testRoom", "查询数据 :"+student.toString());
//查询2
List<Student> studens = dao.getById(new int[]{25,26,27});
Log.d("testRoom","查询数据2 :" + studens.toString());
// 删除
//获取所有
List<Student> allLast = dao.getAll();
for (int i =0; i < allLast.size(); i ++) {
dao.delete(allLast.get(i));
}
}
}
}
三、Room的使用(kotlin)
四、使用database 插件查看数据库
1、AS 右侧 ,点击 “device File Explore”,选择 /data/data/包名,找到databases该路径下面保存的即为代码中创建的数据库。
2、将databases下面的三个文件导出到电脑桌面;
3、按下面步骤操作
五、数据库升级
以本文为例。当数据表中需要新增一列数据时,需要数据库升级,下面是数据库升级的方法。
1、在Studen.java中新增一个字段int grade:
//定义字段
@ColumnInfo(name="grade")
private int grade;
//构造函数
public Student(int uid,String name, int age, String address, String number,int grade) {
this.uid = uid;
this.name = name;
this.age = age;
this.address = address;
this.number = number;
this.grade = grade;
}
public Student(String name, int age, String address, String number,int grade) {
this.name = name;
this.age = age;
this.address = address;
this.number = number;
this.grade = grade;
}
//开放方法
public void setGrade(int grade) {
this.grade = grade;
}
public int getGrade() {
return grade;
}
2、修改TestDB.java,使用SQL脚本完成数据变化
static final Migration MIGRATION_1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
//在这里使用SQL脚本完成数据的变化
database.execSQL("alter table Student add column grade integer not null default 1");
}
};
3、修改TestDB.java,创建数据库方法
private static TestDB mInstance;
public static synchronized TestDB getTestDB(Context context) {
if (mInstance == null) {
mInstance = Room.databaseBuilder(context.getApplicationContext()
,TestDB.class
,"testDB")
//可以设置强制主线程,默认是让你用子线程(如果运行在主线程,需要加上下面这句话)
// .allowMainThreadQueries()
// 2、修改版本号:标记修改版本号(正常方式升级)
.addMigrations(MIGRATION_1_2)
//暴力版本升级(会丢失数据)
// .fallbackToDestructiveMigration()
.build();
}
return mInstance;
}
4、修改TestDB.java,修改数据库版本号
@Database(entities = {Student.class},version = 2/*1、修改版本号:从1 修改到2*/,exportSchema = false)
5、Activity中重新创建数据库
// 创建数据库
/* TestDB testDB = Room.databaseBuilder(getApplicationContext()
,TestDB.class
,"testDB")
//可以设置强制主线程,默认是让你用子线程
// .allowMainThreadQueries()
.build();*/
TestDB testDB = TestDB.getTestDB(MainActivityTest.this);
六、数据库升级(删掉一列数据–一个字段)
// ROOM 是不能降级的,我非要删除一个字段,却要保证数据的稳定性,这个是特殊情况
// 特殊手法降级(不验证了,需要的时候再验证)
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// SQL 四步法
// 1.先建立临时表
// database.execSQL("create table student_temp (uid integer primary key not null,name text,pwd text,addressId)");
// 2.把之前表的数据(SQL语句的细节,同学们可以上网查询下)
// database.execSQL("insert into student_temp (uid,name,pwd,addressid) " + " select uid,name,pwd,addressid from student");
// 3.删除student 旧表
// database.execSQL("drop table student");
// 4.修改 临时表 为 新表 student
// database.execSQL("alter table student_temp rename to student");
}
};