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

如何将存储50万+数据的SQLite数据库迁移至Room数据库?

将现有SQLite数据库(50万+数据)迁移至Room的实现方案

针对大数量级的SQLite到Room迁移,分两种场景给出实操步骤,同时兼顾性能与数据完整性:

场景1:原SQLite与Room结构完全匹配

如果原表的列名、数据类型、主键约束和Room实体完全一致,可直接让Room接管现有数据库:

  1. 定义匹配的Room实体
    确保@Entity的tableName与原SQLite表名完全一致,字段名、类型严格对应原表:

    @Entity(tableName = "user_info")
    data class User(
        @PrimaryKey(autoGenerate = true) val id: Long = 0,
        val username: String,
        val register_time: Long,
        val is_active: Int
    )
    
  2. 配置Room数据库类
    指定数据库名称与原SQLite文件名一致,版本号对齐原数据库的user_version(无版本号则设为1)。若需要升级版本,添加空Migration避免Room销毁数据:

    @Database(entities = [User::class], version = 2)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
    
        companion object {
            fun getInstance(context: Context): AppDatabase {
                return Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "old_user_db.db" // 原SQLite文件名
                )
                .addMigrations(MIGRATION_1_2)
                .build()
            }
    
            // 空迁移:仅处理版本号变更,不修改表结构
            val MIGRATION_1_2 = object : Migration(1, 2) {
                override fun migrate(database: SupportSQLiteDatabase) {}
            }
        }
    }
    
  3. 验证迁移结果
    启动应用后,通过Room DAO执行count()查询,确认数据总数与原数据库一致,随机抽查几条数据验证内容正确性。

场景2:原SQLite与Room结构存在差异

若原表结构需要调整(如列名修改、类型转换、字段增删),需批量读取原数据并转换后插入Room:

  1. 批量读取原数据
    通过原生SQLiteOpenHelper或Room的SupportSQLiteDatabase访问原表,逐批读取数据:

    suspend fun migrateOldData(oldDbPath: String, appDb: AppDatabase) {
        val oldDb = SQLiteDatabase.openDatabase(oldDbPath, null, SQLiteDatabase.OPEN_READONLY)
        val cursor = oldDb.rawQuery("SELECT id, name, reg_date FROM old_user_table", null)
        
        val batchSize = 1000
        val userList = mutableListOf<User>()
        val userDao = appDb.userDao()
    
        // Room事务内批量插入,避免频繁IO
        withTransaction {
            while (cursor.moveToNext()) {
                val id = cursor.getLong(cursor.getColumnIndexOrThrow("id"))
                // 转换原数据格式,比如将字符串日期转为时间戳
                val regTime = cursor.getString(cursor.getColumnIndexOrThrow("reg_date")).toTimestamp()
                val username = cursor.getString(cursor.getColumnIndexOrThrow("name")).trim()
    
                userList.add(User(id, username, regTime, 1))
                
                // 每1000条执行一次插入,控制内存占用
                if (userList.size >= batchSize) {
                    userDao.insertBatch(userList)
                    userList.clear()
                }
            }
            // 插入剩余数据
            if (userList.isNotEmpty()) {
                userDao.insertBatch(userList)
            }
        }
        cursor.close()
        oldDb.close()
    }
    
  2. 定义Room批量插入DAO
    在DAO中添加批量插入方法,提升插入效率:

    @Dao
    interface UserDao {
        @Insert
        suspend fun insertBatch(users: List<User>)
    }
    

核心注意事项

  • 数据库路径:确保原SQLite文件位于Room默认路径(/data/data/[包名]/databases/),若在其他位置,需先关闭原数据库连接,再复制文件到目标路径,避免文件锁定。
  • 事务强制使用:所有数据插入必须在事务中执行,否则50万条数据的插入会触发ANR。
  • 内存控制:批量读取时限制每批数据量(如1000条),避免一次性加载全量数据导致OOM。
  • 版本管理:严格对齐原数据库版本与Room的版本号,Migration必须覆盖所有版本升级路径,防止Room自动销毁重建数据库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 08:50:28