簡介
Room庫在SQLite上提供了一個抽象層,允許在充分利用SQLite的功能的同時進行更健壯的數(shù)據(jù)庫訪問??梢栽谶\行的app設備上創(chuàng)建一個應用數(shù)據(jù)緩存,這個緩存作為app的唯一數(shù)據(jù)來源,不管用戶是否有連接網(wǎng)絡,都允許用戶在app中查看相關(guān)信息。
Room有三個主要的組成部分:Database,Entity,DAO。
-
Database:數(shù)據(jù)庫容器,并作為到應用程序的持久關(guān)系數(shù)據(jù)的底層連接的主要訪問點。
使用@Database注釋的類應該滿足以下條件:
- 擴展RoomDatabase的抽象類
- 在注釋中包含與數(shù)據(jù)庫關(guān)聯(lián)的實體列表
- 包含一個具有0個參數(shù)的抽象方法,并返回用@Dao注釋的類
在運行時,您可以通過調(diào)用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()來獲取數(shù)據(jù)庫實例。
- Entity:表示數(shù)據(jù)庫中的表。
- DAO:包含用于訪問數(shù)據(jù)庫的方法。

引用
在project的build.gradle添加google的maven倉庫
allprojects {
repositories {
google()
jcenter()
}
}
在module的build.gradle添加Room的引用,Room還提供了Rxjava2和Guava的數(shù)據(jù)處理
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使用實體類的名字作為數(shù)據(jù)庫表的名字,如果想更改表名,可以使用@Entity(tableName = "users")更改。
- 主鍵:每個實體都需要定義最少一個主鍵,可以直接在字段使用@PrimaryKey標注主鍵,想Room分配自動ID可使用autoGenerate屬性,也可以使用復合主鍵@Entity(primaryKeys = ["second_name","first_name" ])
- 字段名:字段的名字默認的也是類中屬性的名字如果想設置其他名字,可使用@ColumnInfo(name = "first_name"),Room為每個字段在表中創(chuàng)建對應的字段;如果其中一些屬性不想被創(chuàng)建在表中怎么辦,那就是使用 @Ignore 注解此屬性
- 索引和唯一約束:使用 @Entity 的 indices 來創(chuàng)建索引,并列出索引或者組合索引包含的列,可以使用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 定義對象間的級聯(lián)操作
@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的數(shù)據(jù)訪問類
@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將把所有的參數(shù)在一次事物中插入到數(shù)據(jù)庫中,Insert的參數(shù)onConflict用來指定當發(fā)生沖突是的策略。比如將@Index的unique屬性設置為true,當產(chǎn)生沖突時,默認情況下為OnConflictStrategy.ABORT會導致崩潰,這里設置為OnConflictStrategy.REPLACE,當發(fā)生沖突時替換老數(shù)據(jù)
- 更新:使用@Update注解方法,可以使用參數(shù)實體的值更新主鍵值和參數(shù)實體的主鍵相同的行
- 刪除:@Delete注解方法,可以刪除主鍵值和參數(shù)實體的主鍵相同的行
-
查詢:@Query支持查詢語句,刪除語句和更新語句,不支持插入語句。傳入?yún)?shù)使用“:參數(shù)名”來進行綁定。
- 可觀察查****詢
在執(zhí)行查詢時,想讓UI在數(shù)據(jù)更改時自動更新??梢栽诓樵兎椒ㄊ褂?LiveData 類行的返回值。當數(shù)據(jù)更新時 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
}
創(chuàng)建完完成后使用以下代碼獲取數(shù)據(jù)庫實例,并且使用單例來訪問
var db = Room.databaseBuilder(
getApplicationContext(),
AppDatabase::class.java, "database-name"
).build()
遷移數(shù)據(jù)庫
在APP升級時可能需要更改數(shù)據(jù)庫來策應新的功能。如果不希望數(shù)據(jù)庫中的數(shù)據(jù)丟失,
Room 允許我們編寫 Migration ,以此來遷移數(shù)據(jù);如果使用fallbackToDestructiveMigration(),數(shù)據(jù)庫的內(nèi)容都被清空。
每個遷移類制定一個開始版本和結(jié)束版本。在運行時,Room會運行每個Migration類的migrate()方法,并使用正確的順序?qū)?shù)據(jù)庫遷移到更高版本。
首先,需要更新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提供可選參數(shù),支持多版本遷移,傳入多個migration。
var db = Room.databaseBuilder(
getApplicationContext(),
AppDatabase::class.java, "database-name"
).allowMainThreadQueries()
.addMigrations(MIGRATION_1_2).build()
Room的基本用法介紹已經(jīng)END。