使用Liquibase为已有数据的表新增自增唯一键报错如何解决
问题原因
- 你的变更集执行顺序不符合MySQL逻辑:先新增非空且带唯一约束的
id列时,MySQL会自动为所有已有记录填充默认值0,多条记录的id都为0直接触发唯一键冲突报错。 - 自增属性是在列创建完成后才添加的,已经生成的
0值不会被自动覆盖,自然不会出现预期的递增效果。
解决方案
调整变更集的执行逻辑,先给列加自增属性,等所有旧行自动填充递增数值后,再补充非空、唯一约束,也可以直接在列定义阶段就指定自增属性,让MySQL在加列时就完成旧行的数值填充。
版本1:精简配置(适配大部分Liquibase版本)
<changeSet author="user" id="1"> <addColumn tableName="event"> <column name="id" type="BIGINT" autoIncrement="true"> <constraints nullable="false" unique="true" uniqueConstraintName="event_id_auto_increment" /> </column> </addColumn> </changeSet>
版本2:分步配置(兼容老旧版本Liquibase)
如果你的Liquibase版本不支持直接在addColumn中同时指定autoIncrement和约束,可以拆分为多步执行:
<changeSet author="user" id="1"> <!-- 第一步:先新增无约束的可空id列 --> <addColumn tableName="event"> <column name="id" type="BIGINT" /> </addColumn> <!-- 第二步:添加自增属性,MySQL会自动为所有旧行填充递增的数值 --> <addAutoIncrement incrementBy="1" tableName="event" columnName="id" columnDataType="BIGINT" /> <!-- 第三步:修改列属性,补充非空、唯一约束 --> <addNotNullConstraint tableName="event" columnName="id" columnDataType="BIGINT" /> <addUniqueConstraint tableName="event" columnNames="id" constraintName="event_id_auto_increment" /> </changeSet>
注意事项
- 如果之前的变更已经执行失败,表中已经生成了全为0的
id列,先手动删除该列后再执行新的变更集。 - 可以给修改后的变更集分配新的id,避免Liquibase因为原变更集已经标记为部分执行而跳过。
- 如果表数据量很大,建议在业务低峰期执行,避免锁表影响线上服务。
内容的提问来源于stack exchange,提问作者user
相关产品推荐
相关产品推荐

