一.简介:
Room 在SQLite上提供了一个抽象层,以便在充分利用SQLite的强大功能的同时,可以流畅地访问数据库。
Room包含3个主要组件:
数据库:包含数据库持有者,并做为应用已保留持久性关系型数据的底层链接的主要接入点。
@Database注释
1.是扩展RoomDatabase的抽象类。
2.在注释中添加与数据库关联的实体表。
3.包含具备0个参数且返回使用@Dao 注释的类的抽象方法。
在运行时,您能够经过调用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()获取Database的实例。
@Entity:表示数据库中的表
@Dao:包含用于访问数据库的方法
二:依赖Room数据库
1.在App模块下bulid.Gradle 添加项目的依赖android
//添加Room依赖 implementation 'androidx.room:room-runtime:2.2.5' annotationProcessor 'androidx.room:room-compiler:2.2.5'
三:建立一个实体类Entity数据库
@Entity public 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.主键:每个实体必须定义至少一个字段做为主键。segmentfault
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为trueide
@Entity(indices = {@Index(value = "name",unique = true)}) public class User { private String name; }
5.定义对象之间的关系
因为SQLite是关系型数据库,你能够指定对象以前的关系,Room是明确禁止直接使用关系,但Room仍然容许你在实体之间定义外键。
例如:若是有另外一个实体叫作Book,你能够在User实体下使用@ForeignKey注解定义他们之间的关系。post
@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字段ui
public class Address { public String street; public String state; public String city; @ColumnInfo(name = "post_code") public int postCode; } @Entity public 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注解this
@Ignore//指示Room须要忽略的字段 private int age;
四:建立一个Dao接口
Dao包含用于访问数据库的方法,建立一个操做实体类用@Dao进行注解
@Insert插入语句注释
@Delete删除语句注释
@Update()更新语句注释
@Query("SELECT * FROM user WHERE first_name=:name")查询语句spa
@Dao public 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的抽象类 }
注意:
一、编译时会检查SQL语句是否正确
二、不要在主线程中进行数据库操做
三、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:不负青春,不负韶华;不负梦想,不负将来。