ignore仅跳过非致命错误(如唯一键冲突),将错误降级为警告使语句继续执行;它不处理语法错误等致命错误,且不支持事务内粒度回滚。

IGNORE 能跳过唯一键冲突、类型转换失败、数据截断等非致命错误,但不会跳过语法错误、表不存在、权限不足这类致命错误。它把本该中断操作的错误降级为警告,让语句继续执行——这是它最核心也最容易被误用的行为。
INSERT IGNORE 什么时候真正“跳过”了一行?
很多人以为只要看到 Query OK, 0 rows affected 就说明数据被跳过了,其实不然。MySQL 把冲突当作警告处理,不是错误,所以语句能成功返回,但你需要主动查证是否真有跳过:
- 执行后立刻运行
SHOW WARNINGS,如果看到Warning | 1062 | Duplicate entry ...,说明确实因主键或唯一索引冲突被跳过 - 检查返回值:
mysql_affected_rows()(C API)或cursor.rowcount(Python MySQLdb/PyMySQL)返回 0,才代表该条被忽略;返回 1 是正常插入,>1 是批量中部分成功 - 不要依赖“没报错=全成功”,尤其在批量
INSERT IGNORE INTO t VALUES (...), (...), (...)中,可能只有中间某几行被静默丢弃
UPDATE IGNORE 和 DELETE IGNORE 的实际效果差异
UPDATE IGNORE 在遇到唯一键冲突时会跳过那条更新(比如 SET email='x' 但该 email 已被别人占了),而 DELETE IGNORE 主要用于外键约束场景:当要删的父记录被子表引用,且子表没设 ON DELETE CASCADE 时,普通 DELETE 会报错,加 IGNORE 后就只发警告、不删也不中断。
-
UPDATE IGNORE对性能影响不大,但逻辑风险高:你本想改 A 字段,结果因唯一约束失败,A 没变,B 字段也没动,整个更新“消失”得无声无息 -
DELETE IGNORE几乎只在外键场景下有意义;对无外键的表,它和普通DELETE行为一致(因为没东西可“忽略”) - 三者都**不支持事务回滚粒度控制**:哪怕只有一行出问题,整条语句里其他成功操作仍会提交(除非你在外部显式开启事务并手动回滚)
为什么不能把 IGNORE 当成 ON DUPLICATE KEY UPDATE 的廉价替代?
两者表面都是“防重复”,但语义完全不同:INSERT IGNORE 是“有冲突就扔掉”,ON DUPLICATE KEY UPDATE 是“有冲突就改”。比如邮箱唯一,你希望新数据覆盖旧名字:
-
INSERT IGNORE INTO users (email, name) VALUES ('a@b.com', 'NewName')→ 如果邮箱已存在,整行丢弃,旧名字保留 -
INSERT INTO users (email, name) VALUES ('a@b.com', 'NewName') ON DUPLICATE KEY UPDATE name = VALUES(name)→ 邮箱冲突时,只更新 name 字段 - 性能上,后者多一次 UPDATE 操作,但意图明确;前者快,却容易掩盖业务逻辑缺失——你以为只是“去重”,实际可能是“以新替旧”
最常被忽略的一点:IGNORE 不会告诉你哪条被跳了、为什么跳了、跳了多少条。如果你没在代码里捕获警告、没做 SHOW WARNINGS 或检查 mysql_info(),那些被吞掉的数据就真的消失了,连日志都不会留痕迹。











