往用户表插一条测试数据,SQL 客户端弹红:Duplicate entry 'test01' for key 'uk_username'。字段没设主键,怎么还被拦?因为拦它的是唯一索引,不是主键。

MySQL 的 1062 错误就是这个意思:准备写入的值,在某个唯一约束里已经存在。key 后面跟的是索引名,uk_username 一看就是建表时给用户名加的唯一索引。先执行 SHOW CREATE TABLE 用户表,把索引部分看完,再决定是改数据还是改逻辑。

先确认是哪个索引在报

SHOW INDEX FROM 表名,看 Key_name、Column_name 和 Non_unique。Non_unique 为 0 就是唯一索引;联合唯一索引要看所有列的组合,单看一列可能觉得没重复。还有一种坑:字段排序规则不区分大小写,Test01 和 test01 在数据库眼里是同一个值。

三种处理方式,别选错

确定是重复数据,先 SELECT 出来核对,再删或改;要允许重复提交又不报错,可以用 INSERT IGNORE,但它会连其他错误一起吞掉。想存在就更新,用 INSERT ... ON DUPLICATE KEY UPDATE。REPLACE INTO 看着省事,实际是先删后插,触发器、自增 ID、外键都会受影响。

并发下的重复要靠约束兜底

先查再插的写法,两个请求同时进来照样能插进去两条。真正可靠的是数据库唯一索引,业务层再捕获 1062 做幂等处理。把索引删掉换程序判断,等于把保险丝换成一根铜线,平时没事,出事就是脏数据。

导入数据时批量报错

用 Excel 或脚本导历史数据,报错行号往往对不上。先把源数据按唯一键分组,找出数量大于 1 的记录;再确认空字符串和 NULL 的区别,唯一索引下多个 NULL 一般允许,多个空串不行。处理完再跑一次,别用 IGNORE 一把梭,错了也不知道。

看到 Duplicate entry,先读 key 后面的索引名,再去表结构里找它。九成的答案都在那一行里,剩下的一成是业务上本来就该防重复。