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

基于Room Migration处理应用更新中的数据库与文件迁移问题问询

用Migration对象同步处理数据库迁移与JPEG文件重定位

如果你在应用更新时需要同时搞定数据库字段调整和JPEG文件的迁移,用Room的Migration对象来统一处理绝对是个靠谱的方案——既能借助数据库事务保证操作的原子性,又能同步完成文件系统的修改,完全避免数据不一致的坑。

下面是整理后的简化版Migration类实现,补充了完整的核心逻辑:

class VersionOneToTwo(private val appDataDir: File) : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.beginTransaction()
        try {
            // 第一步:调整数据库中跟踪文件的表结构(这里以重命名URI列为例)
            renameUriColumnInMediaTable(database)
            
            // 第二步:遍历数据库中的JPEG记录,完成文件重定位并更新数据库
            relocateJpegFiles(database)
            
            database.setTransactionSuccessful()
        } finally {
            database.endTransaction()
        }
    }

    private fun renameUriColumnInMediaTable(database: SupportSQLiteDatabase) {
        // 执行SQL修改表字段:把旧的URI列重命名为新列
        database.execSQL("ALTER TABLE media RENAME COLUMN old_file_uri TO new_file_uri")
    }

    private fun relocateJpegFiles(database: SupportSQLiteDatabase) {
        // 查询所有标记为JPEG的文件记录
        val cursor = database.query("SELECT id, old_file_uri FROM media WHERE file_type = 'JPEG'")
        cursor.use {
            while (it.moveToNext()) {
                val fileId = it.getLong(it.getColumnIndexOrThrow("id"))
                val oldUriPath = it.getString(it.getColumnIndexOrThrow("old_file_uri"))
                val oldFile = File(appDataDir, oldUriPath)
                
                // 构建新的文件存储目录(比如按日期分类存放)
                val newDir = File(appDataDir, "migrated_jpegs/${SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(Date())}")
                if (!newDir.exists()) newDir.mkdirs()
                
                val newFile = File(newDir, oldFile.name)
                // 移动文件到新位置
                if (oldFile.renameTo(newFile)) {
                    // 同步更新数据库中的文件路径
                    database.execSQL(
                        "UPDATE media SET new_file_uri = ? WHERE id = ?",
                        arrayOf(newFile.relativeTo(appDataDir).path, fileId)
                    )
                } else {
                    // 文件移动失败时抛出异常,触发事务回滚,避免数据不一致
                    throw IllegalStateException("Failed to relocate JPEG file: ${oldFile.path}")
                }
            }
        }
    }
}

这里有几个关键细节需要注意:

  • 事务原子性:整个操作被包裹在数据库事务中,只要数据库修改或文件迁移任一环节出问题,事务就会回滚,不会出现半完成的状态。
  • 文件与数据库同步:每完成一个文件的重定位,就立刻更新对应的数据库记录,确保两者状态完全匹配。
  • 灵活的错误处理:示例中文件移动失败会直接抛出异常回滚事务,你也可以根据业务需求改成记录错误日志并跳过该文件,具体看你的容错要求。
  • 依赖注入:通过构造函数传入appDataDir,避免在Migration类里硬编码路径,不仅更灵活,也方便写单元测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:47:48