You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移含用户数据的Room数据库至带预填充新表的数据库

解决方案

核心思路

直接从新版本的预填充数据库(assets中的更新版文件)读取新增表的预填充数据,批量插入到用户的现有数据库里,彻底避免手动编写数百条插入语句。

具体步骤

1. 准备新版本预填充数据库

把包含新增users表及对应预填充数据的数据库文件另存为inspection_v2.db,放入项目的assets文件夹。

2. 修改Migration逻辑

在迁移类中,先创建目标表,再从assets里的新版本数据库读取数据并批量插入。需要通过Context访问assets,直接将Context传入Migration即可。

示例代码:

class Migration1To2(private val context: Context) : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 1. 创建新增的users表(保留原有建表逻辑)
        database.execSQL("CREATE TABLE IF NOT EXISTS 'users' ('id' INTEGER NOT NULL UNIQUE, 'name' TEXT NOT NULL, 'specid' TEXT NOT NULL, PRIMARY KEY('id' AUTOINCREMENT))")

        // 2. 从assets的新版本数据库读取预填充数据并插入到当前数据库
        context.assets.open("inspection_v2.db").use { inputStream ->
            // 将assets中的数据库复制到临时文件,避免直接操作只读的assets文件
            val tempFile = File(context.cacheDir, "temp_inspection_v2.db")
            tempFile.outputStream().use { outputStream ->
                inputStream.copyTo(outputStream)
            }

            // 打开临时数据库作为只读模式
            val tempDb = SQLiteDatabase.openDatabase(
                tempFile.path,
                null,
                SQLiteDatabase.OPEN_READONLY
            )

            // 查询新增表的所有预填充数据
            tempDb.query("users", null, null, null, null, null, null).use { cursor ->
                // 用事务包裹插入操作,保证数据一致性
                database.beginTransaction()
                try {
                    val insertStatement = database.compileStatement(
                        "INSERT INTO users (id, name, specid) VALUES (?, ?, ?)"
                    )
                    while (cursor.moveToNext()) {
                        insertStatement.bindLong(1, cursor.getLong(cursor.getColumnIndexOrThrow("id")))
                        insertStatement.bindString(2, cursor.getString(cursor.getColumnIndexOrThrow("name")))
                        insertStatement.bindString(3, cursor.getString(cursor.getColumnIndexOrThrow("specid")))
                        insertStatement.executeInsert()
                        insertStatement.clearBindings()
                    }
                    database.setTransactionSuccessful()
                } finally {
                    database.endTransaction()
                }
            }

            // 清理临时资源
            tempDb.close()
            tempFile.delete()
        }
    }
}

3. 初始化数据库时传入Context到Migration

Room.databaseBuilder(context, InspectionDatabase::class.java, "inspection_db.db")
    .createFromAsset("inspection.db") // 仅首次创建数据库时生效,不影响已有数据库的迁移
    .setJournalMode(JournalMode.TRUNCATE)
    .allowMainThreadQueries()
    .addMigrations(Migration1To2(context)) // 传入Context实例
    .build()

注意事项

  • 确保新版本预填充数据库中新增表的结构,和迁移时创建的表结构完全一致,避免插入数据时出现字段不匹配的错误。
  • 迁移过程中必须用事务包裹批量插入操作,防止中途出错导致数据不一致。
  • 临时文件使用App的缓存目录,避免权限问题,使用后及时删除释放空间。

内容的提问来源于stack exchange,提问作者Whitt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:57:15