? ? ? ?App迭代過程中,難免需要對數(shù)據(jù)庫進(jìn)行更新,有可能是字段的增加,修改或刪除,也有可能需要新建一張表,這就涉及到數(shù)據(jù)庫的遷移Migrate,最簡單粗暴的方法是在Room的配置項(xiàng)中添加fallbackToDestructiveMigration()方法,如下
Room.databaseBuilder(context.applicationContext,
AppDatabase::class.java, "exercise.db")
.fallbackToDestructiveMigration() //添加此方法
.build()
? ? ? ?為什么說是簡單粗暴呢,因?yàn)樗侵苯觿h除之前的數(shù)據(jù)庫,重新再創(chuàng)建新的數(shù)據(jù)庫,這在大部分情況下絕對是災(zāi)難性的做法,所以更好的做法是addMigrations(Migration... migrations),具體以下步驟:
一、version升級+1 (我這邊是3 -> 4)
@Database(entities = [HistoryEntity::class,CollectEntity::class], version = 4)
abstract class AppDatabase: RoomDatabase() {
//code
}
二、自定義Migration,如下三種情況:
1.增加一個字段update_time
private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE history ADD COLUMN update_time INTEGER NOT NULL DEFAULT 0")
}
}
2.創(chuàng)建一個新表collect
private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"CREATE TABLE collect (collect_id INTEGER NOT NULL DEFAULT 0,line_name_collect TEXT NOT NULL DEFAULT '', upper_or_down_collect TEXT NOT NULL DEFAULT '', PRIMARY KEY(collect_id))")
}
}
3.更改一個字段類型
private val MIGRATION_4_3: Migration = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
//創(chuàng)建一個備份的新表
database.execSQL(
"CREATE TABLE collect_new_one (collect_id INTEGER NOT NULL DEFAULT 0,line_name_collect TEXT NOT NULL DEFAULT '', upper_or_down_collect TEXT NOT NULL DEFAULT '', PRIMARY KEY(collect_id))")
// 把舊表的數(shù)據(jù)拷貝到新表
database.execSQL(
"INSERT INTO collect_new_one (collect_id , line_name_collect, upper_or_down_collect) SELECT collect_id, line_name_collect, upper_or_down_collect FROM collect")
// 刪除掉舊表
database.execSQL("DROP TABLE collect")
// 重命名新表(完成謀權(quán)篡位)
database.execSQL("ALTER TABLE collect_new_one RENAME TO collect")
}
}
三、將自定義好的Migration加入配置
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, "exercise.db"
) .addMigrations(MIGRATION_1_2,MIGRATION_2_3,MIGRATION_3_4)
.build()
? ? ? ?這就是完整的Room數(shù)據(jù)庫遷移,但是這當(dāng)中可能會碰到幾個異常報(bào)錯,比如
Room Database Migration doesnt properly handle ALTER TABLE migration
解決方法可以定位到我第一個例子(增加一個字段)的sql語句,在后面加入INTEGER NOT NULL DEFAULT 0 保證當(dāng)它為null時賦予0,否則Room會直接拋異常;其他的報(bào)錯基本能從報(bào)錯信息理解出來。
? ? ? ?順便曬出AppDatabase代碼
@Database(entities = [HistoryEntity::class, CollectEntity::class], version = 4)
abstract class AppDatabase : RoomDatabase() {
abstract fun historyDao(): HistoryDao
abstract fun collectDao(): CollectionDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(App.instance).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, "exercise.db"
).addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4)
.build()
private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE history ADD COLUMN update_time INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"CREATE TABLE collect (collect_id INTEGER NOT NULL DEFAULT 0,line_name_collect TEXT NOT NULL DEFAULT '', upper_or_down_collect TEXT NOT NULL DEFAULT '', PRIMARY KEY(collect_id))"
)
}
}
private val MIGRATION_3_4: Migration = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"CREATE TABLE collect_new_one (collect_id INTEGER NOT NULL DEFAULT 0,line_name_collect TEXT NOT NULL DEFAULT '', upper_or_down_collect TEXT NOT NULL DEFAULT '', PRIMARY KEY(collect_id))"
)
database.execSQL(
"INSERT INTO collect_new_one (collect_id , line_name_collect, upper_or_down_collect) SELECT collect_id, line_name_collect, upper_or_down_collect FROM collect"
)
database.execSQL("DROP TABLE collect")
database.execSQL("ALTER TABLE collect_new_one RENAME TO collect")
}
}
}
}
總結(jié)
? ? ? ?這是我自己練手項(xiàng)目中截取的一個記錄,項(xiàng)目里使用到j(luò)etpack,后面有時間還會一一記錄與分享,對于Room的簡單使用上總體感覺還算方便快速,就是這個數(shù)據(jù)遷移會踩點(diǎn)坑,比較麻煩