INSERT IGNORE仅跳过主键或唯一键冲突,将其降级为警告而非错误,其他错误仍报错;它不修改数据、无副作用,适用于“只新增不覆盖”场景。

INSERT IGNORE 为什么能跳过主键冲突
它不是“忽略所有错误”,而是只对违反 PRIMARY KEY 或 UNIQUE 约束的插入失败静默处理,其他错误(比如字段类型不匹配、NOT NULL 违反)照常报错。本质是 MySQL 把这类冲突降级为警告,而不是异常中断。
常见错误现象:Duplicate entry '123' for key 'PRIMARY' 不再抛出,但执行后 mysql_affected_rows() 返回 0(表示没插入新行);用 SHOW WARNINGS 能看到被忽略的具体冲突。
- 必须确保表有明确的
PRIMARY KEY或UNIQUE索引,否则INSERT IGNORE和普通INSERT行为一致 - 不适用于想“更新已有数据”的场景——它只跳过,不改
- 在事务中使用时,被忽略的语句仍算作已执行,不会回滚整条语句,但会影响
LAST_INSERT_ID()
INSERT IGNORE 和 REPLACE INTO 的关键区别
REPLACE INTO 看似也能处理重复主键,但底层是“删+插”:先尝试 DELETE 匹配的旧行,再 INSERT 新行。这会触发 DELETE 和 INSERT 的所有约束检查、外键级联、触发器,还可能改变 AUTO_INCREMENT 值。
-
INSERT IGNORE:无副作用,快,适合“只新增不覆盖” -
REPLACE INTO:会重置自增 ID、触发删除类逻辑,适合“强制覆盖” - 如果表有外键且设了
ON DELETE CASCADE,REPLACE INTO可能意外删掉关联数据,INSERT IGNORE完全不会
替代方案:ON DUPLICATE KEY UPDATE 更灵活
当你要“存在就更新某些字段”时,INSERT ... ON DUPLICATE KEY UPDATE 是更精准的选择。它只在发生主键/唯一键冲突时执行指定的 UPDATE 子句,其余情况照常插入。
示例:INSERT INTO users (id, name, updated_at) VALUES (123, 'Alice', NOW()) ON DUPLICATE KEY UPDATE name = VALUES(name), updated_at = NOW();
-
VALUES(col)引用的是本次 INSERT 中该列的值,不是当前行原值 - 只能针对一个冲突键生效;如果多个唯一索引都可能冲突,得确保逻辑能覆盖全部路径
- 性能上比
INSERT IGNORE稍低,因为要多做一次 UPDATE 操作,但语义清晰,不易误用
容易被忽略的兼容性细节
MySQL 5.7+ 默认开启严格模式(STRICT_TRANS_TABLES),但 INSERT IGNORE 仍有效。不过某些云数据库或中间件(如 ProxySQL、某些读写分离代理)可能拦截或重写该语法,导致行为不一致。
- 在 MariaDB 中行为完全一致,可放心迁移
- 如果用 ORM(如 SQLAlchemy、Sequelize),别直接拼 SQL,优先用其提供的 upsert 方法,避免底层驱动对
IGNORE处理不一致 - 批量插入(
INSERT IGNORE ... VALUES (...), (...), ...)中,只要有一行冲突,整批仍继续处理其余行——但要注意返回的受影响行数是“成功插入数”,不是总行数
真正麻烦的不是语法怎么写,而是搞清你到底要“跳过”“覆盖”还是“更新部分字段”。选错方案,后面查数据不一致会花更长时间。











