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

Android Kotlin上线项目合并双Room数据库的迁移方案问询

合并上线项目中两个Room数据库的迁移方案

1. 先规划新数据库结构

  • 梳理DB1和DB2的所有实体(Entity),合并重复表结构,统一命名避免冲突(比如两个模块都有User表时,要确定字段取舍、数据合并规则)。
  • 定义新的Room Database类,包含所有合并后的实体,设置新的数据库名称(比如CombinedDB)和初始版本号(建议基于两个旧库的最高版本+1,或者直接设为1——因为这是全新库,后续按常规规则升级)。

2. 保留旧库定义,实现跨库数据迁移

由于项目已上线,用户设备上同时存在DB1和DB2,不能直接删除旧库,得先读取旧库数据写入新库,完成后再清理旧库:

  • 复制旧库的核心类到新模块:把旧Module1、Module2中的Room实体、DAO、Database类完整复制到合并后的模块中,必须保证旧库的Database类的name参数、实体字段、版本号和线上版本完全一致,这样Room才能找到设备上已存在的旧数据库文件。
    示例旧DB1的Database类:
    @Database(entities = [DB1User::class, DB1Order::class], version = 3)
    abstract class DB1 : RoomDatabase() {
        abstract fun db1UserDao(): DB1UserDao
        abstract fun db1OrderDao(): DB1OrderDao
    }
    
  • 编写数据迁移工具:创建一个工具类,负责读取旧库数据、转换为新库实体、写入新库:
    object DBDataMigrator {
        suspend fun migrateToCombinedDB(context: Context) {
            // 初始化旧库实例(fallbackToDestructiveMigration避免旧库版本变化导致的初始化失败)
            val db1 = Room.databaseBuilder(context, DB1::class.java, "db1_name")
                .fallbackToDestructiveMigration()
                .build()
            val db2 = Room.databaseBuilder(context, DB2::class.java, "db2_name")
                .fallbackToDestructiveMigration()
                .build()
    
            // 读取旧库数据
            val db1Users = db1.db1UserDao().getAllUsers()
            val db2Products = db2.db2ProductDao().getAllProducts()
    
            // 转换为新库实体(处理字段映射、重复数据合并)
            val combinedUsers = db1Users.map { it.toCombinedUser() }
            val combinedProducts = db2Products.map { it.toCombinedProduct() }
    
            // 写入新库
            val combinedDB = Room.databaseBuilder(context, CombinedDB::class.java, "combined_db")
                .build()
            combinedDB.runInTransaction {
                combinedDB.combinedUserDao().insertAll(combinedUsers)
                combinedDB.combinedProductDao().insertAll(combinedProducts)
            }
    
            // 清理旧库
            db1.close()
            db2.close()
            context.deleteDatabase("db1_name")
            context.deleteDatabase("db2_name")
        }
    }
    

3. 控制迁移执行时机

  • 在App启动阶段(比如Application的onCreate或主页面onCreate),检查旧库是否存在、新库是否已初始化,满足条件则在后台线程执行迁移:
    class MyApp : Application() {
        override fun onCreate() {
            super.onCreate()
            CoroutineScope(Dispatchers.IO).launch {
                val hasOldDBs = databaseList().contains("db1_name") || databaseList().contains("db2_name")
                val hasCombinedDB = databaseList().contains("combined_db")
                if (hasOldDBs && !hasCombinedDB) {
                    DBDataMigrator.migrateToCombinedDB(this@MyApp)
                }
            }
        }
    }
    

4. 处理边缘场景

  • 重复数据冲突:如果两个旧库有同业务的表(比如都有User),提前定好合并规则——比如保留DB1的数据、合并字段(取最新更新时间的记录),或让用户手动选择。
  • 迁移失败回滚:迁移前备份旧库文件,一旦迁移失败,恢复旧库避免数据丢失。
  • 多版本兼容:如果旧库有多个历史版本,确保复制的旧Database类能兼容所有旧版本,或在读取时处理不同版本的字段差异。
  • 全场景测试:覆盖仅装过Module1、仅装过Module2、同时装过两个模块、全新安装的用户场景,确保迁移逻辑稳定。

5. 后续版本维护

  • 迁移完成后,新数据库的版本更新按常规Room迁移流程处理(编写Migration类,添加到databaseBuilder)。
  • 几个版本后,确认所有用户都完成迁移,可移除旧库的实体、Database类和迁移代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 17:45:07