“key 1”指表中第一个唯一性索引(主键或首个unique索引),由show index结果顺序决定,不一定是primary;需查key_name和column_name确认具体索引字段及是否为复合索引或含null值。

查清楚“key 1”到底指哪个索引
报错里写的 for key 'PRIMARY' 或 for key '1' 容易让人误以为一定是主键,其实不一定。MySQL 的 key 1 是指表中第一个唯一性索引(可能是主键,也可能是第一个 UNIQUE 约束),顺序由 SHOW INDEX 输出决定。
先执行:SHOW INDEX FROM your_table;
重点看 Key_name 和 Column_name 列:如果某行的 Key_name 是 PRIMARY,那冲突就在主键;如果是 uk_email 或类似名字,那就得去查 email 字段有没有重复值。
- 别只盯着
id字段,复合唯一索引(比如(user_id, order_date))也可能触发这个错误,单个字段不重复,组合起来重复照样报错 - 注意 NULL 值:MySQL 允许多个
NULL存在唯一索引列中,但某些旧版本或特殊 SQL 模式下可能误判,尤其当字段定义为NOT NULL却又插了空字符串时,''和NULL容易混淆
确认重复值是来自目标库还是备份文件
导入 SQL 文件时报 Duplicate entry '123' for key 'PRIMARY',第一反应不该是改语句,而是查这行数据到底在哪——是目标库已有,还是备份里多写了一次?
立刻执行:SELECT * FROM your_table WHERE id = 123;
- 如果有结果,说明目标库非空,你是在没清空的情况下直接恢复,属于操作流程错误
- 如果没结果,但导入仍失败,问题在备份文件:可能是导出时用了
--replace但源库本身就有重复主键;或者导出没关约束(SET UNIQUE_CHECKS=0;缺失),导致导入中途校验失败 - 别手动编辑几百 MB 的 SQL 文件加
INSERT IGNORE,用命令行参数更稳:mysql --force -u root db_name
INSERT 时冲突:用对语句比硬删数据更安全
日常插入遇到重复,不是非得先 DELETE 再 INSERT。MySQL 提供了更可控的替代方案,关键看业务逻辑是否允许覆盖或跳过。
-
INSERT IGNORE INTO ...:冲突时静默跳过,不报错也不插入,适合幂等写入场景(如日志、状态上报) -
REPLACE INTO ...:先删后插,会触发DELETE+INSERT两轮操作,可能意外删除关联数据(比如外键级联) -
INSERT ... ON DUPLICATE KEY UPDATE ...:最推荐,只更新指定字段,不干扰其他列,例如:INSERT INTO user (id, name) VALUES (1, 'Alice') ON DUPLICATE KEY UPDATE name = VALUES(name);
注意:REPLACE 和 ON DUPLICATE KEY UPDATE 都要求冲突字段上有唯一索引(主键或 UNIQUE),否则不生效。
UPDATE 报 Duplicate entry?你在改唯一键字段
执行 UPDATE user SET email = 'a@b.com' WHERE id = 5; 却报 Duplicate entry 'a@b.com' for key 'uk_email',说明表里已经有另一条记录的 email 是 a@b.com —— 你不是在插入,而是在把某条记录的唯一键字段改成一个已被占用的值。
- 这类错误常出现在批量更新脚本里,比如同步用户邮箱,没做
SELECT预检就直接UPDATE - 修复方式不是调大自增,而是加条件过滤:
UPDATE user SET email = 'a@b.com' WHERE id = 5 AND email != 'a@b.com'; - 更稳妥的做法是先查重:
SELECT id FROM user WHERE email = 'a@b.com' AND id != 5;,有结果就得人工介入或设计合并逻辑
真正容易被忽略的是:UPDATE 触发唯一键冲突,和 INSERT 的处理逻辑完全不同——它不涉及自增计数器,也不需要重置 AUTO_INCREMENT,纯粹是业务值撞车。











