INSERT IGNORE仅对PRIMARY KEY或UNIQUE约束冲突静默跳过,其他错误(如字段超长、NOT NULL插NULL)仍报错;无对应索引时等同普通INSERT;复合唯一索引需整组值重复才触发忽略;允许多个NULL值不视为重复;逐行判断,不影响后续行插入。

INSERT IGNORE 不是万能容错开关,它只对 PRIMARY KEY 或 UNIQUE 约束冲突静默跳过,其他错误(比如字段超长、NOT NULL 插 NULL、类型不匹配)照常报错。没建对应索引?它就和普通 INSERT 完全一样。
为什么 INSERT IGNORE 没生效,还报 Duplicate entry 错误
最常见原因是表上根本没建 PRIMARY KEY 或 UNIQUE 索引。MySQL 只有在检测到这类约束被违反时,才会把错误降级为警告并跳过——否则直接抛异常。
- 用
SHOW CREATE TABLE table_name确认存在明确的PRIMARY KEY或UNIQUE KEY定义 - 注意:
UNIQUE字段允许NULL,多个NULL值不视为重复,INSERT IGNORE会照常插入 - 如果用的是复合唯一索引(如
UNIQUE (a, b)),必须整组值都重复才触发忽略 - 某些旧版存储引擎(如 MyISAM)行为略有差异,建议统一用 InnoDB
批量插入时,某行被忽略,会影响后面所有行吗
不会。INSERT IGNORE 是逐行判断的:某行因主键或唯一键冲突被跳过,后续行仍会独立检查并可能成功插入。返回的 affected_rows 是实际新增行数,不是总行数减去冲突数。
- 例如:
INSERT IGNORE INTO t VALUES (1,'a'),(1,'b'),(2,'c')—— 第一行冲突被忽略,第二行也冲突被忽略,第三行成功,最终affected_rows = 1 - 但要注意:事务中它不回滚前面已成功的行,如果你依赖“全成功或全失败”,得自己加逻辑控制
- 单次批量别塞太多行(建议 ≤ 1000),避免锁表时间过长或日志膨胀
INSERT IGNORE 和 ON DUPLICATE KEY UPDATE 的关键区别
INSERT IGNORE 只能跳过,不能更新;ON DUPLICATE KEY UPDATE 才能实现“有则更新、无则插入”。两者语法互斥,不能混用。
-
INSERT IGNORE后面不能跟UPDATE子句,否则直接语法报错 -
ON DUPLICATE KEY UPDATE中的VALUES(col)指本次INSERT提供的值,不是原记录当前值 - 如果表有多个唯一索引(比如
email和phone都设了UNIQUE),任一冲突都会触发UPDATE,需确保更新逻辑覆盖所有路径 - 性能上,
ON DUPLICATE KEY UPDATE比INSERT IGNORE多一次 UPDATE 操作,但语义更精确,不易误用
如何确认某条 INSERT IGNORE 真的被跳过了
不能只看是否报错,得查返回值和警告。MySQL 把冲突当作警告处理,而不是错误中断。
- 执行后调用
mysql_affected_rows()或mysqli->affected_rows:返回0表示该语句没插入新行(即被忽略),返回1或更高表示成功插入 - 立即执行
SHOW WARNINGS,能看到类似Warning 1062: Duplicate entry 'xxx' for key 'PRIMARY'的提示 - 注意:在严格模式(
STRICT_TRANS_TABLES)下,INSERT IGNORE依然有效,但其他非冲突类错误(如截断)可能被拒绝
真正容易被忽略的是 NULL 和空字符串的语义差异:同一个 UNIQUE 字段,'' 和 NULL 在 MySQL 中不等价,前者会参与唯一性校验,后者通常不会——这会导致你以为“应该被忽略”的行其实插进去了,或者反过来。











