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

Room迁移唯一约束冲突求助:为每行生成唯一UUID

解决数据库迁移时UUID重复导致的唯一约束错误

你的问题根源在于:${UUID.randomUUID()}是在Kotlin代码编译SQL字符串时仅生成一次,最终所有插入行的id都会使用同一个UUID,直接触发主键唯一约束报错。以下是几种可行的修复方案:

方案1:使用SQLite内置UUID生成函数(推荐)

如果你的SQLite版本在3.31.0及以上(Room 2.3.0+默认适配的版本满足此要求),可以直接在SQL语句中调用uuid()函数,为每一行生成独立的UUID:

修改插入逻辑的代码:

val sql = "INSERT INTO $MIGRATION_TABLE_CODES (id, text, format, type, date, note, isFavorite) " +
        "SELECT uuid(), text, format, type, date, note, isFavorite " +
        "FROM $MIGRATION_TABLE_CODES_OLD"

该函数会为每一行返回唯一的标准UUID字符串,完全满足主键唯一性要求。

方案2:兼容低版本SQLite的替代方案

若你的SQLite版本不支持uuid()函数,可使用hex(randomblob(16))生成32位十六进制随机字符串作为唯一ID:

val sql = "INSERT INTO $MIGRATION_TABLE_CODES (id, text, format, type, date, note, isFavorite) " +
        "SELECT hex(randomblob(16)), text, format, type, date, note, isFavorite " +
        "FROM $MIGRATION_TABLE_CODES_OLD"

生成的字符串虽不符合UUID的标准格式,但具备同等唯一性,可正常作为主键使用。

方案3:逐行读取插入(Kotlin层面生成UUID)

如果上述SQL方案无法适配,可通过游标遍历旧表数据,在代码循环中为每一行生成独立UUID后插入新表:

// 开启事务提升批量插入性能
database.beginTransaction()
try {
    val cursor = database.query("SELECT text, format, type, date, note, isFavorite FROM $MIGRATION_TABLE_CODES_OLD")
    while (cursor.moveToNext()) {
        val text = cursor.getString(cursor.getColumnIndexOrThrow("text"))
        val format = cursor.getInt(cursor.getColumnIndexOrThrow("format"))
        val type = cursor.getInt(cursor.getColumnIndexOrThrow("type"))
        val date = cursor.getLong(cursor.getColumnIndexOrThrow("date"))
        val note = cursor.getString(cursor.getColumnIndexOrThrow("note"))
        val isFavorite = cursor.getInt(cursor.getColumnIndexOrThrow("isFavorite"))
        
        val insertSql = "INSERT INTO $MIGRATION_TABLE_CODES (id, text, format, type, date, note, isFavorite) " +
                "VALUES (?, ?, ?, ?, ?, ?, ?)"
        database.execSQL(insertSql, arrayOf(
            UUID.randomUUID().toString(),
            text,
            format,
            type,
            date,
            note,
            isFavorite
        ))
    }
    cursor.close()
    database.setTransactionSuccessful()
} finally {
    database.endTransaction()
}

此方式性能略低于纯SQL方案,适合数据量较小的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:43:19