Android Room使用
简介Room库在SQLite上提供了一个抽象层,允许在充分利用SQLite的功能的同时进行更健壮的数据库访问。可以在运行的app设备上创建一个应用数据缓存,这个缓存作为app的唯一数据来源,不管用户是否有连接网络,都允许用户在app中查看相关信息。Room有三个主要的组成部分:Database,Entity,DAO。Database:数据库容器,并作为到应用程序的持久关系数据的底层连接的...
简介
Room库在SQLite上提供了一个抽象层,允许在充分利用SQLite的功能的同时进行更健壮的数据库访问。可以在运行的app设备上创建一个应用数据缓存,这个缓存作为app的唯一数据来源,不管用户是否有连接网络,都允许用户在app中查看相关信息。
Room有三个主要的组成部分:Database,Entity,DAO。
-
Database:数据库容器,并作为到应用程序的持久关系数据的底层连接的主要访问点。
使用@Database注释的类应该满足以下条件:
- 扩展RoomDatabase的抽象类
- 在注释中包含与数据库关联的实体列表
- 包含一个具有0个参数的抽象方法,并返回用@Dao注释的类
在运行时,您可以通过调用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()来获取数据库实例。
- Entity:表示数据库中的表。
- DAO:包含用于访问数据库的方法。
Room不同组成的相关关系图
引用
在project的build.gradle添加google的maven仓库
allprojects {
repositories {
google()
jcenter()
}
}
在module的build.gradle添加Room的引用,Room还提供了Rxjava2和Guava的数据处理
dependencies {
def room_version = "2.1.0-alpha07"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// 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"
}
Enity
下面定义一个User的实体
@Entity
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "second_name") val secondName: String?,
@Ignore val desc: String?
)
- **表名:**Room使用实体类的名字作为数据库表的名字,如果想更改表名,可以使用@Entity(tableName = “users”)更改。
- **主键:**每个实体都需要定义最少一个主键,可以直接在字段使用@PrimaryKey标注主键,想Room分配自动ID可使用autoGenerate属性,也可以使用复合主键@Entity(primaryKeys = [“second_name”,“first_name” ])
- **字段名:**字段的名字默认的也是类中属性的名字如果想设置其他名字,可使用@ColumnInfo(name = “first_name”),Room为每个字段在表中创建对应的字段;如果其中一些属性不想被创建在表中怎么办,那就是使用 @Ignore 注解此属性
- **索引和唯一约束:**使用 @Entity 的 indices 来创建索引,并列出索引或者组合索引包含的列,可以使用unique属性设置唯一约束Index(value = [“name”], unique = true)
@Entity(indices = [Index("name"), Index(value = ["first_name", "second_name"])])
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "second_name") val secondName: String?,
@Ignore val desc: String?
)
- **外键:**可以使用@ForeignKey 定义对象间的级联操作
@Entity(foreignKeys = [ForeignKey(entity = User::class, parentColumns = ["uid"], childColumns = ["user_id"])])
data class Order(
@PrimaryKey val orderNo: String,
@ColumnInfo val address: String,
@ColumnInfo(name = "user_id") val userId: Int
)
- **嵌套对象:**可以使用@Embedded 嵌套其他实体对象,可以通过设置属性 prefix 加前缀的方式保证字段名不重复。
@Embedded(prefix = "order") val order: Order?
DAO
定义一个User的数据访问类
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM user where first_name LIKE :first AND second_name LIKE :last LIMIT 1 ")
fun findByName(first: String, last: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
@Update
fun updateUsers(vararg users: User)
}
- **插入:**使用@Insert注解,Room将把所有的参数在一次事物中插入到数据库中,Insert的参数onConflict用来指定当发生冲突是的策略。比如将@Index的unique属性设置为true,当产生冲突时,默认情况下为OnConflictStrategy.ABORT会导致崩溃,这里设置为OnConflictStrategy.REPLACE,当发生冲突时替换老数据
- **更新:**使用@Update注解方法,可以使用参数实体的值更新主键值和参数实体的主键相同的行
- 删除:@Delete注解方法,可以删除主键值和参数实体的主键相同的行
- 查询:@Query支持查询语句,删除语句和更新语句,不支持插入语句。传入参数使用“:参数名”来进行绑定。
- 可观察查****询
在执行查询时,想让UI在数据更改时自动更新。可以在查询方法使用 LiveData 类行的返回值。当数据更新时 Room 会自动生成所需的代码已更新LiveData。
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
fun getList(userIds: IntArray): LiveData<List<User>>
- 响应查询
可以从定义的查询中返回 RxJava2 的 Publisher 和 Flowable 对象
@Query("SELECT * FROM user where first_name LIKE :first AND second_name LIKE :last LIMIT 1 ")
fun getByName(first: String, last: String): Flowable<User>
Database
@Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
创建完完成后使用以下代码获取数据库实例,并且使用单例来访问
var db = Room.databaseBuilder(
getApplicationContext(),
AppDatabase::class.java, "database-name"
).build()
迁移数据库
在APP升级时可能需要更改数据库来策应新的功能。如果不希望数据库中的数据丢失,
Room 允许我们编写 Migration ,以此来迁移数据;如果使用fallbackToDestructiveMigration(),数据库的内容都被清空。
每个迁移类制定一个开始版本和结束版本。在运行时,Room会运行每个Migration类的migrate()方法,并使用正确的顺序将数据库迁移到更高版本。
首先,需要更新Database的版本号
@Database(entities = arrayOf(User::class), version = 2)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
其次添加一个version:1->2的migration
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE User " + " ADD COLUMN mobile TEXT")
}
}
最后把migration 添加到 databaseBuilder,addMigrations提供可选参数,支持多版本迁移,传入多个migration。
var db = Room.databaseBuilder(
getApplicationContext(),
AppDatabase::class.java, "database-name"
).allowMainThreadQueries()
.addMigrations(MIGRATION_1_2).build()
Room的基本用法介绍已经END。
更多推荐
所有评论(0)