MySQL · 错误码速查
MySQL 错误 1062:先从报错里读出是哪张表的哪个唯一索引,再判断是「真重复」还是排序规则认为重复
ERROR 1062 (23000): Duplicate entry 'a@x.com' for key 'u.uk_email' 表示这次写入和主键或唯一索引 uk_email 上已有的值撞了。MySQL 8.0 起报错里的键名是「表名.索引名」。注意判重按列的排序规则:默认 utf8mb4_0900_ai_ci 不区分大小写和重音,'A@X.COM' 和 'a@x.com' 会被判为重复。报错只回滚当前这一条语句,事务本身不回滚。
官方原文
Error number: 1062; Symbol: ER_DUP_ENTRY; SQLSTATE: 23000
Message: Duplicate entry '%s' for key %d
The message returned with this error uses the format string for ER_DUP_ENTRY_WITH_KEY_NAME.官方错误参考同时说明:实际返回的消息使用 1586 ER_DUP_ENTRY_WITH_KEY_NAME 的格式 "Duplicate entry '%s' for key '%s'",所以你看到的是索引名而不是数字。
出处:MySQL 8.4 Error Reference:Server Error Message Reference 最后核对:
| 错误号 / 符号 | 1062 / ER_DUP_ENTRY(服务端错误) | 出处 |
|---|---|---|
| SQLSTATE | 23000(完整性约束违反) | 出处 |
| 消息格式 | 按 1586 ER_DUP_ENTRY_WITH_KEY_NAME:Duplicate entry '%s' for key '%s' | 出处 |
| 回滚范围 | 官方:duplicate-key 错误回滚这条 SQL 语句(未加 IGNORE 时),事务不回滚;单条语句回滚不释放已加的锁 | 出处 |
| 相邻错误 | 1022 ER_DUP_KEY;1859 ER_DUP_UNKNOWN_IN_INDEX;1586 ER_DUP_ENTRY_WITH_KEY_NAME | 出处 |
先读懂报错:'u.uk_email' 是「表.索引」,PRIMARY 是主键
在 MySQL 8.0.46 测试库上,往 u(email UNIQUE KEY uk_email) 重复写 a@x.com,返回的是 Duplicate entry 'a@x.com' for key 'u.uk_email'。引号里第一个是冲突的值(复合唯一索引会用 - 把各列拼起来,本机复现 UNIQUE(shop, sku) 显示为 '1-S-1'),第二个是「表名.索引名」;如果是主键冲突,索引名显示为 PRIMARY。
拿到索引名后,用下面的只读 SQL 查它由哪些列组成,再用这几列去原表找已存在的那一行。很多 1062 不是业务真的重复,而是唯一索引比你以为的多了或少了一列。
SELECT INDEX_NAME, SEQ_IN_INDEX, COLUMN_NAME, COLLATION
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'u' AND NON_UNIQUE = 0
ORDER BY INDEX_NAME, SEQ_IN_INDEX;
SELECT id, email FROM u WHERE email = 'a@x.com';大小写、重音不同也报 1062:判重按排序规则,不按字节
MySQL 8.0 默认排序规则 utf8mb4_0900_ai_ci 不区分大小写(ci)也不区分重音(ai)。本机复现:已有 a@x.com 时写 A@X.COM 报 1062;先写入 é@x.com 后再写 e@x.com 也报 1062。反过来,'b@x.com '(末尾多一个空格)可以和 b@x.com 共存,因为 0900 系列排序规则是 NO PAD,尾随空格参与比较。
| 写入的值 | 已存在的值 | 结果(utf8mb4_0900_ai_ci) |
|---|---|---|
A@X.COM | a@x.com | 1062,大小写不敏感 |
e@x.com | é@x.com | 1062,重音不敏感 |
b@x.com (尾随空格) | b@x.com | 写入成功,NO PAD 下不相等 |
如果业务上大小写不同就是不同的值(例如区分大小写的编码、Base64 片段),该列应改用 _bin 或 _as_cs 排序规则;如果业务上应当视为相同(例如邮箱),就在写入前统一大小写并 TRIM,否则尾随空格会让「看起来一样」的两行同时存在。改排序规则属于表结构变更,先在测试库验证。
回滚到哪一步,为什么自增 id 跳号
- 多行 INSERT:
INSERT … VALUES ('c1'),('c2'),('a@x.com')第 3 行冲突,本机复现 c1、c2 也都没有写入——整条语句回滚。 - 事务内:
START TRANSACTION后先成功插入一行,下一条 INSERT 报 1062,前一行仍然在,COMMIT后可见。官方 InnoDB 错误处理一节写明 duplicate-key 错误只回滚这条语句,并且单条语句回滚不释放已经加上的锁——应用捕获 1062 后要尽快决定 ROLLBACK 还是继续,别让事务挂着。 - 自增跳号:失败的 INSERT 已经分配过自增值。本机复现成功写入的 4 行 id 是 1、3、5、7,中间的 2、4、6 被失败语句用掉了。
ON DUPLICATE KEY UPDATE走更新分支时同样会消耗自增值。
所以「id 不连续」本身不是数据丢失。真要排查丢数据,应该对照业务流水或 binlog,而不是看 id 是否连号。
INSERT IGNORE 和 ON DUPLICATE KEY UPDATE:返回行数各代表什么
| 写法 | 冲突时的行为 | affected rows(本机复现) |
|---|---|---|
INSERT IGNORE | 不报错,跳过这行,留下 1062 Warning | 0 |
… ON DUPLICATE KEY UPDATE(插入新行) | 正常插入 | 1 |
… ON DUPLICATE KEY UPDATE(命中并修改) | 更新已有行 | 2 |
… ON DUPLICATE KEY UPDATE(命中但值没变) | 不改 | 0 |
INSERT IGNORE会把很多错误一起降级为警告(不只是 1062,严格模式下的 1366 等也会),容易把脏数据静默写进去;只想忽略重复时,优先用ON DUPLICATE KEY UPDATE id = id一类写法,并检查返回行数。- 官方文档建议尽量避免在有多个唯一索引的表上用
ON DUPLICATE KEY UPDATE;VALUES(col)写法已弃用,改用行别名INSERT … AS new ON DUPLICATE KEY UPDATE c = new.c。
加唯一索引时报 1062:先用 GROUP BY 找出已有重复
ALTER TABLE p ADD UNIQUE KEY uk_sku (sku) 时如果表里已经有重复,同样报 Duplicate entry 'S-1' for key 'p.uk_sku',但它只告诉你第一个撞上的值。先用只读 SQL 把所有重复组列出来,清理完再加索引。
SELECT sku, COUNT(*) AS cnt, GROUP_CONCAT(id ORDER BY id) AS ids
FROM p
GROUP BY sku
HAVING COUNT(*) > 1
ORDER BY cnt DESC
LIMIT 100;如果唯一列用的是不区分大小写的排序规则,GROUP BY 也按同一排序规则分组,S-1 和 s-1 会落在同一组——这正是 ALTER 会报错的原因。
常见问题
Duplicate entry for key 'PRIMARY' 和 for key 'xxx' 有什么区别?
PRIMARY 表示主键冲突;其他名字是唯一索引名,MySQL 8.0 起显示为「表名.索引名」。先查这个索引由哪些列组成,再用这些列去找已存在的行。
为什么大小写不同也报 1062?
判重按列的排序规则。MySQL 8.0 默认 utf8mb4_0900_ai_ci 不区分大小写和重音,'A@X.COM' 与 'a@x.com'、'e' 与 'é' 都算相同;需要区分时改用 _bin 或 _as_cs 排序规则。
报 1062 之后事务会回滚吗?
不会。官方说明 duplicate-key 错误只回滚出错的那条语句(多行 INSERT 整条不写入),事务里之前成功的语句仍然有效;但这条语句加过的锁不会因此释放,应用应尽快 ROLLBACK 或继续提交。
为什么报了 1062 之后自增 id 跳号?
失败的 INSERT 和 ON DUPLICATE KEY UPDATE 的更新分支都会消耗已分配的自增值。id 不连续本身不代表丢数据。
INSERT IGNORE 能不能用来去重?
能跳过重复行,但它会把严格模式下的其他错误(如 1366 类型不对)一起降为警告并写入调整后的值。只想处理重复时,用 ON DUPLICATE KEY UPDATE 并检查返回行数更安全。
下一步
价格以对应页面当前标价为准。
出处(最后核对 2026-11-01)
- MySQL 8.4 Error Reference:Server Error Message Reference
- MySQL 8.4 Reference Manual 17.20.5:InnoDB Error Handling
- MySQL 8.4 Reference Manual:INSERT … ON DUPLICATE KEY UPDATE
- MySQL 8.4 Reference Manual:AUTO_INCREMENT Handling in InnoDB
本页摘录并解读上面列出的官方文档,不是官方页面;官方文档更新后以官方为准。本页内容都来自官方文档,没有我们自己的测试结果。