iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >【Jetpack】使用 Room 中的 Migration 升级数据库异常处理 ( 多个数据库版本的迁移 | fallbackToDestructiveMigration() 函数处理升级异常 )
  • 279
分享到

【Jetpack】使用 Room 中的 Migration 升级数据库异常处理 ( 多个数据库版本的迁移 | fallbackToDestructiveMigration() 函数处理升级异常 )

androidsqliteJetpackRoomMigration原力计划 2023-09-13 09:09:35 279人浏览 八月长安
摘要

文章目录 一、Room#Migration 迁移工具升级数据库二、多个数据库版本的迁移三、数据库异常处理 - RoomDatabase.Builder#fallbackToDestructiv

文章目录





一、Room#Migration 迁移工具升级数据库



Room Migration 数据库迁移工具 Android Jetpack Architecture Components ( 架构组件 ) 的一部分 , 它是一个方便的 数据库迁移工具 , 用于为 Android 中使用 Room 框架创建的数据库 提供 自动化迁移方案 ;


Room Migration 数据库迁移工具用途如下 :

  • 数据库修改 : 修改数据库表结构 ;
  • 迁移代码 : 为每个数据库版本编写 迁移代码 ;
  • 自动更新 : 执行应用时 自动 检测数据库版本号 并 自动进行数据迁移 ;

迁移前保存数据库数据 : 当在应用程序中更改 Room 数据库中的架构时 , 将需要执行数据库迁移以保留旧数据并防止应用程序崩溃 ;

自动运行 : Room Migration 数据库迁移工具 会 自动 创建迁移文件 并将其应用于数据库 , 以使 sqlite 数据库 保持最新架构 ;





二、多个数据库版本的迁移



在原始 版本 1 的数据库中 , 有如下 : id , name , age , 三个字段 ;

@Entity(tableName = "student")class Student {        @PrimaryKey(autoGenerate = true)    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)    var id: Int = 0        @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)    lateinit var name: String        @ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)    var age: Int = 0}

从数据库版本 1 升级到 数据库版本 2 , 添加了 sex 字段 ;

                val MIGRATION_1_2: Migration = object : Migration(1, 2) {            override fun migrate(database: SupportSQLiteDatabase) {                Log.i("Room_StudentDatabase", "数据库版本 1 升级到 版本 2")                database.execSQL("alter table student add column sex integer not null default 1")            }        }

从数据库版本 2 升级到数据库版本 3 , 增加了 degree 字段 ;

                val MIGRATION_2_3: Migration = object : Migration(2, 3) {            override fun migrate(database: SupportSQLiteDatabase) {                Log.i("Room_StudentDatabase", "数据库版本 2 升级到 版本 3")                database.execSQL("alter table student add column degree integer not null default 1")            }        }

用户之前运行该数据库 , 有可能安装的是 数据库 版本 1 / 版本 2 / 版本 3 任意一个版本的数据库 ;


数据库 版本 1 -> 数据库 版本 3 升级过程 :

如果用户之前运行的是数据库版本 1 , 那么运行该最新应用时 , 先执行

val MIGRATION_1_2: Migration = object : Migration(1, 2)

迁移对象对应的迁移操作 , 先从数据库版本 1 升级到 数据库版本 2 ;

然后再 执行

val MIGRATION_2_3: Migration = object : Migration(2, 3)

迁移对象对应的迁移操作 , 从数据库版本 2 升级到 数据库版本 3 ;


数据库 版本 2 -> 数据库 版本 3 升级过程 :

如果之前用户手机中的数据库版本是 版本 2 , 那么 运行该最新应用时 , 直接执行

val MIGRATION_2_3: Migration = object : Migration(2, 3)

迁移对象对应的迁移操作 , 从数据库版本 2 升级到 数据库版本 3 ;





三、数据库异常处理 - RoomDatabase.Builder#fallbackToDestructiveMigration() 函数



在上一篇博客 【Jetpack】使用 Room 中的 Migration 升级数据库 ( 修改 Entity 实体类 - 更改数据模型 | 创建 Migration 迁移类 | 修改数据库版本 | 代码示例 ) 中 , 讲解了如何使用 Migration 升级数据库 ;

首先 , 创建 Migration 迁移类 ,

    compaNIOn object {                val MIGRATION_1_2: Migration = object : Migration(1, 2) {            override fun migrate(database: SupportSQLiteDatabase) {                Log.i("StudentDatabase", "数据库版本 1 升级到 版本 2")                database.execSQL("alter table student add column sex integer not null default 1")            }        }}

然后 , 修改数据库版本 ;

@Database(entities = [Student::class], version = 1, exportSchema = false)abstract class StudentDatabase: RoomDatabase() {

如果 只在 RoomDatabase 的 @Database 注解上 修改了数据库版本 , 而没有创建对应的 Migration 迁移类 , 那么就会出现 IllegalStateException 异常 ;

报错信息如下 :

2023-06-05 10:47:13.635 E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0    Process: kim.hsl.rvl, PID: 31463    java.lang.RuntimeException: Exception while computing database live data.        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)        at java.lang.Thread.run(Thread.java:930)     Caused by: java.lang.IllegalStateException: A migration from 2 to 4 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.        at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:117)        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:124)        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:435)        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:331)        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)        at androidx.room.RoomDatabase.query(RoomDatabase.java:324)        at androidx.room.util.DBUtil.query(DBUtil.java:83)        at kim.hsl.rvl.StudentDao_Impl$4.call(StudentDao_Impl.java:125)        at kim.hsl.rvl.StudentDao_Impl$4.call(StudentDao_Impl.java:122)        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)         at java.lang.Thread.run(Thread.java:930)             --------- beginning of system

在这里插入图片描述

处理上述异常需要在 创建 RoomDatabase.Builder 时 , 执行一下 RoomDatabase.Builder#fallbackToDestructiveMigration() 函数 , 之后在使用 Migration 迁移数据库时 , 如果出现异常 , 就会重建数据库表 , 但是之前的数据库数据也相应会被清空 ;

                    // 创建数据库                    instance = Room.databaseBuilder(                        context.applicationContext,                        StudentDatabase::class.java,                        "student_database.db")                        .addMigrations(MIGRATION_1_2)                        .addMigrations(MIGRATION_2_3)                        .fallbackToDestructiveMigration()                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库                      // 如果要在主线程操作数据库需要调用该函数                        .build()

再次运行时 , 打印的日志结果如下 :

2023-06-05 10:52:41.757 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: []2023-06-05 10:52:42.154 I/Room_MainActivity: 插入数据 S1 : Student(id=0, name='Tom', age=18)2023-06-05 10:52:42.158 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18)]2023-06-05 10:52:42.664 I/Room_MainActivity: 插入数据 S2 : Student(id=0, name='Jerry', age=16)2023-06-05 10:52:42.666 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jerry', age=16)]2023-06-05 10:52:43.174 I/Room_MainActivity: 更新数据 S2 : Student(id=2, name='Jack', age=60)2023-06-05 10:52:43.176 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jack', age=60)]2023-06-05 10:52:43.681 I/Room_MainActivity: 删除数据 id = 12023-06-05 10:52:43.683 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=2, name='Jack', age=60)]2023-06-05 10:52:44.182 I/Room_MainActivity: 主动查询 : LiveData : androidx.room.RoomTrackingLiveData@b957950 , 实际数据 : null2023-06-05 10:52:44.183 I/Room_MainActivity: 主动查询2 : [Student(id=2, name='Jack', age=60)]

第一行打印的日志Observer#onChanged 回调, List: [] , 当前数据库是空的 , 之前的数据都被清空 , 此时打印的日志都是本次应用运行时新插入的数据 ;





四、完整代码示例



代码地址 : https://github.com/han1202012/Room_ViewModel_LiveData

来源地址:https://blog.csdn.net/han1202012/article/details/131040728

--结束END--

本文标题: 【Jetpack】使用 Room 中的 Migration 升级数据库异常处理 ( 多个数据库版本的迁移 | fallbackToDestructiveMigration() 函数处理升级异常 )

本文链接: https://www.lsjlt.com/news/405672.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作