Room數(shù)據(jù)庫遷移

? ? ? ?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)坑,比較麻煩

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容