Room 是Google简化Sqlite专门提供的封装框架。
拥有Sqlite的所有功能
使用简单,通过注解的方法实现相关功能,类似于GreenDao,编译时自动生成实现类。
支持LiveData LifeCycle Paging
1.依赖
def room_version = "2.3.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor "androidx.room:room-compiler:$room_version"
2.了解注解
@Database 数据库的主对象
@Database(entities = {Cache.class}, version = 1,exportSchema =true) entities 是个数组,涉及哪些表,版本号、导出升级的数据库日志。
@columnInfo(name="info") 更改列的名字
@Dao 操作数据库的对象,如:增删改查
@Embedded 嵌套对象
@Entity 表的对象
@PrimartKey 主键
@Delete 删除
@Ingore 忽略在数据库产生列
@Index 加快查询操作,副作用减慢插入或者更新
@Foreignkey 外键关联
@Tranation
@TypeConverter
2.1 冲突策略
Dao
注解—涉及具体查询方法,是个接口,编译的时候自动生成实现类。当数据主键一致时,会发生冲突,这时候需要冲突策略处理数据。
@Dao
public interface CacheDao {
@Insert(onConflict = OnConflictStrategy.ABORT)
void insert(Cache cache);
}
冲突策略
增加和修改的时候,有可能已经存在的数据,OnConflictStrategy 就是解决这种情况的冲突策略。
int REPLACE = 1;
/**
* OnConflict strategy constant to rollback the transaction.
* 回滚
*/
int ROLLBACK = 2;
/**
* OnConflict strategy constant to abort the transaction.
* 放弃
*/
int ABORT = 3;
/**
* OnConflict strategy constant to fail the transaction.
*/
int FAIL = 4;
/**
* OnConflict strategy constant to ignore the conflict.
*/
int IGNORE = 5;
2.2 foreignKeys
foreignKeys
主要是为了和其他对象有关联的时候使用。下面这句就是当前对象和User对象进行对象,都是通过各自的id进行关联。onDelete 和onUpdate 使用的外键策略。这个策略主要针对当前的表数据的变化引起关联表的变化的策略机制。
@Entity(tableName = "cache",
foreignKeys = {@ForeignKey(entity = User.class,parentColumns = "id",childColumns = "id",
onDelete = ForeignKey.RESTRICT,onUpdate = ForeignKey.RESTRICT)})
- int NO_ACTION = 1; 不处理
- int RESTRICT = 2; 若主表删除,相关的关联表立即也删除。
- int SET_NULL = 3; 设置null
- int SET_DEFAULT = 4; 设置默认值
- int CASCADE = 5; 类似RESTRICT,与之相关的每个关联表都响应。
3.数据库的创建
创建一个抽象类继承RoomDatabase对象,静态代码块,初始化数据库对象,三个参数,
1-上下文,
2-当前对象,
3-数据库名称。
下面还有针对数据库的配置。
@Database(entities = {Cache.class}, version = 1,exportSchema =true)
public abstract class CacheDatabase extends RoomDatabase {
private static final CacheDatabase database;
static {
//创建一个内存数据库
//但是这种数据库的数据只存在于内存中,也就是进程被杀之后,数据随之丢失
//Room.inMemoryDatabaseBuilder()
database = Room.databaseBuilder(AppGlobals.getApplication(), CacheDatabase.class, "cache")
//是否允许在主线程进行查询
//.allowMainThreadQueries()
//数据库创建和打开后的回调
//.addCallback()
//设置查询的线程池
//.setQueryExecutor()
//room的日志模式
//.setJournalMode()
//数据库升级异常之后的回滚
//.fallbackToDestructiveMigration()
//数据库升级异常后根据指定版本进行回滚
//.fallbackToDestructiveMigrationFrom()
//数据库迁移 监听 ,可以进行修改
// .addMigrations(CacheDatabase.sMigration)
.build();
}
public static CacheDatabase get() {
return database;
}
// 获取操作对象
public abstract CacheDao getCacheDao();
}
- @Database(entities = {Cache.class}, 数据库核心对象,entities 表对象
- version = 1, 版本号
- exportSchema =true) exportSchema =true是日志模式,
要实现配置build.gradle–>android–>defaultConfig里
javaCompileOptions{
annotationProcessorOptions{
arguments=["room.schemaLocation":"$projectDir/schemas".toString()]
}
}
2.1数据迁移
.addMigrations
迁移涉及到数据库升级的字段改变。
// 具体实现
static Migration sMigration = new Migration(1, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("alter table teacher rename to student");
}
};
2.2 实体
- 每个实体必须将至少 1 个字段定义为主键。即使只有 1 个字段,您仍然需要为该字段添加 @PrimaryKey 注释
- 如果您想让 Room 为实体分配自动 ID,则可以设置 @PrimaryKey 的 autoGenerate 属性
- Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注释的 tableName 属性 unique 表示唯一
- @ColumnInfo(name = “name”) 修改表字段,默认为属性字段
- @Ignore 忽略该字段产生表里的字段,如果实体继承了父实体的字段,则使用 @Entity 属性的 ignoredColumns 属性
- @NonNull 不能为null
@Entity()
public class User {
@PrimaryKey(autoGenerate = true)
@NonNull
int id;
@ColumnInfo(name = "name")
String firstName;
@Ignore
String lastName;
}
2.3 Dao对象
- DAO 既可以是
接口,也可以是抽象类
。如果是抽象类,则该 DAO 可以选择有一个以 RoomDatabase 为唯一参数的构造函数。 - Room 会在编译时创建每个 DAO 实现。
- @Insert
- 如果 @Insert 方法
只接收 1 个参数,则它可以返回 long
,这是插入项的新 rowId。如果参数是数组或集合
,则应返回 long[] 或 List。 - @Update
它使用与每个实体的主键匹配
的查询。此方法返回一个 int 值,以指示数据库中更新的行数。 - @Delete
会从数据库中删除一组以参数形式给出的实体.它使用主键查找
要删除的实体 - @Query
简单查询
有参数查询:
注意:除非已对构建器调用 allowMainThreadQueries(),否则 Room 不支持在主线程上访问数据库,因为它可能会长时间锁定界面
@Dao
public interface CacheDao {
//冲突策略
@Insert(onConflict = OnConflictStrategy.ABORT)
void insert(Cache cache);
@Query(("select * from cache where 'key'= :key"))
Cache getCache(String key);
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE id IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE name LIKE :first AND lastName LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
//返回列的子集
@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();
}
public class NameTuple {
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
@NonNull
public String lastName;
}
2.4 直接光标访问
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
public Cursor loadRawUsersOlderThan(int minAge);
}
强烈建议不要使用 Cursor API,因为它无法保证行是否存在或者行包含哪些值。只有当您已具有需要光标且无法轻松重构的代码时,才使用此功能
4.查询返回类型
Room 支持各种查询方法的返回类型,包括与特定框架或 API 进行互操作的特殊返回类型
查询类型 | kotlin | rxjava |
---|---|---|
可观察读取 | Flow | Flowable、Publisher、Observable |
单次读取 | suspend fun | Single、Maybe |
单次写入 | suspend fun | Single、Maybe、Completable |
3.1 使用流进行响应式查询
@Query("SELECT * FROM User")
fun getAllUsers(): Flow<List<User>>
3.2 使用 Kotlin 协程进行异步查询
您可以将 suspend Kotlin 关键字添加到 DAO 方法中,以使用 Kotlin 协程功能使这些方法成为异步方法
@Dao
interface MyDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUsers(vararg users: User)
@Update
suspend fun updateUsers(vararg users: User)
@Delete
suspend fun deleteUsers(vararg users: User)
@Query("SELECT * FROM user")
suspend fun loadAllUsers(): Array<User>
}
3.3 使用 LiveData 进行可观察查询
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
}
3.4 使用 RxJava 进行响应式查询
Room 为 RxJava2 类型的返回值提供了以下支持:
@Query 方法:Room 支持 Publisher、Flowable 和 Observable 类型的返回值。
@Insert、@Update 和 @Delete 方法:Room 2.1.0 及更高版本支持 Completable、Single 和 Maybe 类型的返回值。
在这里插入代码片
6.具体使用
CacheDatabase.getCacheDatabase().getCacheDao().insert(cache);
CacheDatabase.getCacheDatabase().getCacheDao().delete(cache);