Room是Jetpack组件中一个对象关系映射(ORM)库。可以很容易将 SQLite 表数据转换为 Java 对象。
@Query
和@Entity
等,它不仅检查语法问题,还会检查是否有该表,这就意味着几乎没有任何运行时错误的风险Room有3个主要组件:
implementation 'android.arch.persistence.room:runtime:1.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
在使用数据的时候,需要主要涉及到Room三个部分:
1.Entity(创建表)
创建表一般会用到下面几个注解:
@Entity(tableName=“表名称”)
定义一个表
@PrimaryKey(autoGenerate=true)
定义主键
@ColumnInfo(name = “列名”)
定义列名
@Ignore
忽略某个字段
@Entity(tableName = UserModel.USER_TABLE_NAME,
indices = {@Index(value = {UserModel.FACE_ID}, unique = true),
@Index(value = {UserModel.NAME}, unique = true)})
public class UserModel implements Parcelable {
public static final String USER_TABLE_NAME = "user" ;
public static final String NAME = "name";
public static final String FACE_ID = "faceId";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = BaseColumns._ID)
public long id;
@NonNull
@ColumnInfo(name = FACE_ID)
public String faceId;
@NonNull
@ColumnInfo(name = NAME)
public String name;
public UserModel(@NonNull String faceId, @NonNull String name) {
this.faceId = faceId;
this.name = name;
}
}
2.Dao
@Insert、@Delete、@Update、@Query 代表我们常用的插入、删除、更新、查询数据库操作。
@Dao
public interface UserDao {
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.NAME + " = :name")
LiveData queryByName2Lv(String name);
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.NAME + " = :name")
UserModel queryByName2Model(String name);
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.FACE_ID + " = :faceId")
LiveData queryByFaceId2Lv(String faceId);
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.FACE_ID + " = :faceId")
UserModel queryByFaceId2Model(String faceId);
@Query("SELECT COUNT(*) FROM " + UserModel.USER_TABLE_NAME)
int count();
@Query("SELECT * FROM " + UserModel.USER_TABLE_NAME)
LiveData> queryAllByLv();
@Query("SELECT * FROM " + UserModel.USER_TABLE_NAME)
List queryAll();
@Update
public int updateUsers(List userModels);
@Insert(onConflict = OnConflictStrategy.REPLACE)
long insertUser(UserModel userModel);
@Insert(onConflict = OnConflictStrategy.REPLACE)
long[] insertAllUser(List userModels);
@Delete
void delete(UserModel... userModels);
@Delete
void deleteAll(List userModels);
@Query("DELETE FROM " + UserModel.USER_TABLE_NAME + " WHERE " +
UserModel.FACE_ID + " = :faceId")
int deleteByFaceId(String faceId);
}
3.DataBase
创建一个抽象类继承自RoomDatabase
给他添加一个注解@Database表名它是一个数据库,注解有两个参数第一个是数据库的实体,它是一个数组,可以传多个,当数据库创建的时候,会默认给创建好对应的表,第二个参数是数据库的版本号
定义跟数据库一起使用的相关的DAO类
创建一个RoomDemoDatabase的单例,防止同时打开多个数据库的实例
使用Room提供的数据库构建器来创建该实例,第一个参数application,第二个参数当前数据库的实体类,第三个参数数据库的名字
exportSchema = true 支持导出Room生成的配置文件
创建好这三个组件,Room的配置基本就已经完成了,通常我们需要的业务逻辑都加写在Dao中的抽象方法中。
4.数据库迁移
在Room中,数据库迁移使用的是Migration对象,定义如下:
添加新的实体类
@Entity(tableName = FaceModel.FACE_TABLE_NAME,
foreignKeys = {
@ForeignKey(entity = UserModel.class,
parentColumns = "faceId",
childColumns = "faceId",
onUpdate = ForeignKey.CASCADE,
onDelete = ForeignKey.CASCADE
)
},
indices = {@Index(value = {"faceId"})}
)
public class FaceModel {
public static final String FACE_TABLE_NAME = "face";
public static final String TYPE = "type";
public static final String FACE_ID = "faceId";
public static final String PATH = "path";
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = BaseColumns._ID)
public long id;
@NonNull
@ColumnInfo(name = PATH)
public String path;
@ColumnInfo(name = TYPE)
public int type;
@NonNull
@ColumnInfo(name = FACE_ID)
public String faceId;
public FaceModel(@NonNull String path, int type, @NonNull String faceId) {
this.path = path;
this.type = type;
this.faceId = faceId;
}
}
配置实体类
@Database(entities = {
UserModel.class, FaceModel.class
},
version = 2, exportSchema = true)
1 startVersion是旧版本号,endVersion是新版本号。数据库版本发生变更(如升级)会回调migrate函数,我们需要在此回调中编写版本变更的相关代码,例如创建表、添加列等等。
public abstract class Migration {
public final int startVersion;
public final int endVersion;
public Migration(int startVersion, int endVersion) {
this.startVersion = startVersion;
this.endVersion = endVersion;
}
public abstract void migrate(@NonNull SupportSQLiteDatabase database);
}
把Migration添加到对应的db中:
val appDb = Room.databaseBuilder(this, AppDatabase::class.java, "myDb.db")
.allowMainThreadQueries()
.addMigrations(object : Migration(1,2){
override fun migrate(database: SupportSQLiteDatabase) {
//升级相关操作
}
})
.build()
2 Sql 升级语句,可以根据Room导出的json文件获取
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
Log.i(TAG, "migrate: ");
// Create the new table
String sql = "CREATE TABLE IF NOT EXISTS face (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `path` TEXT NOT NULL, `type` INTEGER NOT NULL, `faceId` TEXT NOT NULL, FOREIGN KEY(`faceId`) REFERENCES `user`(`faceId`) ON UPDATE CASCADE ON DELETE CASCADE )";
database.execSQL(
sql);
String sql2 = "CREATE INDEX IF NOT EXISTS `index_face_faceId` ON face (`faceId`)";
database.execSQL(
sql2);
}
};
private static RoomDemoDatabase buildDatabase(final Context appContext) {
return Room.databaseBuilder(appContext, RoomDemoDatabase.class, DATABASE_NAME)
.allowMainThreadQueries()
.addMigrations(MIGRATION_1_2)
//.openHelperFactory(new SafeHelperFactory("123456".toCharArray()))
.addCallback(new Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
})
.build();
}
多版本升级
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_1_4)
关联表配置
@Entity(tableName = FaceModel.FACE_TABLE_NAME,
foreignKeys = {
@ForeignKey(entity = UserModel.class,
parentColumns = "faceId",
childColumns = "faceId",
onUpdate = ForeignKey.CASCADE,
onDelete = ForeignKey.CASCADE
)
},
indices = {@Index(value = {"faceId"})}
)
创建嵌套对象
public class UserAndFaceModel {
@Relation(parentColumn = "faceId", entityColumn = "faceId", entity = FaceModel.class)
public List faceModels;
@Embedded
public UserModel userModel;
}
创建关联Dao
@Dao
public interface UserAndFaceDao {
@Transaction // 保障事务
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.NAME + " = :name")
LiveData queryByName2Lv(String name);
@Transaction
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.NAME + " = :name")
UserAndFaceModel queryByName2Model(String name);
@Transaction
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.FACE_ID + " = :faceId")
LiveData queryByFaceId2Lv(String faceId);
@Transaction
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME + " WHERE "+
UserModel.FACE_ID + " = :faceId")
UserAndFaceModel queryByFaceId2Model(String faceId);
@Transaction
@Query("SELECT * FROM "+ UserModel.USER_TABLE_NAME )
List queryAll();
}
关联表数据插入注意
保障事务
RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).runInTransaction(new Runnable() {
@Override
public void run() {
UserModel userModel = new UserModel(1, "1", "2");
RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).userDao().insertUser(userModel);
FaceModel faceModel = new FaceModel("fa", 1, "fa");
RoomDemoDatabase.getInstance(MainActivity.this.getApplicationContext()).faceDao().insertFace(faceModel);
}
});