Android 数据库Room的开发应用详解

一.简介:
Room 在SQLite上提供了一个形象层,以便在充分利用SQLite的弱小性能的同时,可能流畅地拜访数据库。
Room蕴含3个次要组件:
数据库:蕴含数据库持有者,并作为利用已保留持久性关系型数据的底层连贯的次要接入点。
@Database正文
1.是扩大RoomDatabase的抽象类。
2.在正文中增加与数据库关联的实体表。
3.蕴含具备0个参数且返回应用@Dao 正文的类的形象办法。
在运行时,您能够通过调用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()获取Database的实例。
@Entity:示意数据库中的表
@Dao:蕴含用于拜访数据库的办法

二:依赖Room数据库
1.在App模块下bulid.Gradle 增加我的项目的依赖

//增加Room依赖implementation 'androidx.room:room-runtime:2.2.5'annotationProcessor 'androidx.room:room-compiler:2.2.5'


三:创立一个实体类Entity

@Entitypublic class User {    @PrimaryKey(autoGenerate = true)//主键是否主动增长,默认为false private int id; private String name; private int age; public int getId() {        return id; }    public void setId(int id) {        this.id = id; }    public String getName() {        return name; }    public void setName(String name) {        this.name = name; }    public int getAge() {        return age; }    public void setAge(int age) {        this.age = age; }}


1.主键:每一个实体必须定义至多一个字段作为主键。

 1.能够在实体中@PrimaryKey(autoGenerate = true)注解,同时你也能够应用autoGenerate属性,能够通过Room来主动调配ID 2.也能够通过@Entity@Entity(primaryKeys = {"id","name"})如果有组合主键

2.通常Room会应用类名作为数据库的表名,如果你心愿自定义表名在@Entity(tableName = "my_user"),留神:SQLite中,表名是不辨别大小写的
3.Room用变量名称作为数据库表的字段名称,如果你心愿字段名称和变量名称不一样,在变量出增加

public class User { @ColumnInfo(name = "first_name")    private String name;    }

4.索引和唯一性
依据你操作数据的形式你可能须要通过索引来进步查询数据库的速度,通过@Entity增加indices属性,有些字段设置唯一性,能够通过@Index注解下设置unique为true

@Entity(indices = {@Index(value = "name",unique = true)})public class User {private String name;}

5.定义对象之间的关系
因为SQLite是关系型数据库,你能够指定对象之前的关系,Room是明确禁止间接应用关系,但Room依然容许你在实体之间定义外键。
例如:如果有另一个实体叫做Book,你能够在User实体下应用@ForeignKey注解定义他们之间的关系。

@Entity(        foreignKeys = @ForeignKey(entity = User.class, parentColumns = "id",         childColumns = "user_id")//定义外键)public class Book {    @PrimaryKey//定义主键 public int bookId; public String title; @ColumnInfo(name = "user_id")//定义数据库表中的字段名    public int userId; public int getUserId() {        return userId; }    public void setUserId(int userId) {        this.userId = userId; }    public int getBookId() {        return bookId; }    public void setBookId(int bookId) {        this.bookId = bookId; }    public String getTitle() {        return title; }    public void setTitle(String title) {        this.title = title; }}

6.创立嵌套对象
你能够应用@Embedded批注来示意要合成到表中子字段的对象
例如:咱们的User类能够蕴含Address类型的字段,它示意名为street,city,state和postCode的字段的组合。要将组合列别离存储在表中,请在User类中蕴含应用@Embedded正文的Address字段

public class Address {    public String street;    public String state;    public String city;    @ColumnInfo(name = "post_code")    public int postCode;}@Entitypublic class User {    @PrimaryKey    public int id;    public String firstName;    @Embedded    public Address address;}

故这个示意User对象的表蕴含具备以下名称的列:id,firstName,street,state,city和post_code。
@Embedded(prefix = "address_")如果实体具备多个雷同类型的嵌入字段,则能够通过设置prefix属性使得每一个列放弃惟一,把address_嵌入到列名的结尾
7.疏忽成员变量
如果你不想保留某些成员变量,能够应用@Ignore注解

@Ignore//批示Room须要疏忽的字段private int age;

四:创立一个Dao接口
Dao蕴含用于拜访数据库的办法,创立一个操作实体类用@Dao进行注解
@Insert插入语句正文
@Delete删除语句正文
@Update()更新语句正文
@Query("SELECT * FROM user WHERE first_name=:name")查问语句

@Daopublic interface UserDao {    /*插入数据User*/ @Insert void insert(User user); @Query("SELECT * FROM  user")//从user表中查问所有,user是User实体类默认在Room中创立的表,也能够通过@Entity(tableName = "my_user"),指定表名,故这个表名就变成my_user    List<User> getAllUsers(); @Query("SELECT * FROM user WHERE first_name=:name")//设置筛选条件name,来查问这个first_name是表名first_name字段,通过@ColumnInfo(name = "first_name")来设置表字段名    List<User> getUsersByName(String name);}

五:创立一个数据库持有者类

@Database(entities = {User.class},version = 6,exportSchema = false)public abstract class UserDatabase extends RoomDatabase {    private static final String DB_NAME="UserDatabase.db"; private static volatile UserDatabase instance;//创立单例 public static synchronized UserDatabase getInstance(Context context){        if (instance==null){            instance=create(context); }        return instance; } /** * 创立数据库*/    private static UserDatabase create(Context context) {        return Room.databaseBuilder(context,UserDatabase.class,DB_NAME)        .allowMainThreadQueries()//容许在主线程操作数据库,个别不举荐;设置这个后主线程调用增删改查不会报错,否则会报错        .fallbackToDestructiveMigration()//该办法能在降级异样从新创立数据库,但所有的数据都会失落        .addMigrations(new Migration(1,4) {    @Override public void migrate(@NonNull SupportSQLiteDatabase database) {        database.execSQL("alter table user add price TEXT");//增加一个字段 price降级数据库版本到4 }})        .build(); }  public  abstract UserDao getUserDao();//这个是必要的,创立DAO的抽象类}

留神:
1、编译时会查看SQL语句是否正确
2、不要在主线程中进行数据库操作
3、RoomDatabase最好应用单例模式
如果不设置数据库在主线程操作的话就会报错,谬误提醒为

故须要应用数据库最好在new Thread().start()子线程中应用,或者Handler 或者AsyncTask或者RXJava异步实现。
Room数据库降级

//第一步批改版本号为2,要降级的版本@Database(entities = {User.class},version = 2,exportSchema = false)//第二步,增加addMigrations()增加数据库降级 Room.databaseBuilder(context,UserDatabase.class,DB_NAME)        .addMigrations(new Migration(1,2) {            @Override public void migrate(@NonNull SupportSQLiteDatabase database) {                database.execSQL("alter table user add go TEXT");//在user 表中增加一个字段go 类型为TEXT Log.d("aa",database.getVersion()+""); }        })        .build();//第三步在Entity实体类User中增加属性private String go;public String getGo() {    return go;}public void setGo(String go) {    this.go = go;}//这样数据库版本就降级到了2,就能够应用了        

六:Room数据库应用
通过开拓子线程插入一条数据,也能够联合RXJava和Handler和AsyncTask等异步实现

User user=new User();user.setAge(2223);user.setName("eees");user.setGo("wogo");new Thread(new Runnable() {    @Override public void run() {        UserDatabase.getInstance(NineActivity.this).getUserDao().insert(user); Log.d("TAG","插入一条数据"); }}).start();

END:不负青春,不负韶华;不负幻想,不负将来。