迁移含用户数据的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
相关产品推荐
相关产品推荐

