insert ... on duplicate key update 更可靠,因其是原子操作,由mysql内部同一行锁保证并发一致性,避免“查+改”导致的竞态条件与重复键错误。

INSERT ... ON DUPLICATE KEY UPDATE 为什么比先查再改更可靠
因为「查 + 改」在并发下必然产生竞态:两个事务同时查不到记录,都执行 INSERT,触发唯一键冲突或主键重复错误。INSERT ... ON DUPLICATE KEY UPDATE 是原子操作,MySQL 内部用同一行锁保证一致性,不会漏更新也不会报错回滚。
常见错误现象:ERROR 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY' 或 'uk_email' —— 这说明你还在用 SELECT 判断是否存在。
使用场景:用户注册时更新 last_login_time、订单状态去重写入、配置项幂等初始化。
实操建议:
睿拓智能网站系统-网上商城1.0免费版软件大小:5M运行环境:asp+access本版本是永州睿拓信息专为电子商务入门级用户开发的网上电子商城系统,拥有产品发布,新闻发布,在线下单等全部功能,并且正式商用用户可在线提供多个模板更换,可实现一般网店交易所有功能,是中小企业和个人开展个人独立电子商务商城最佳的选择,以下为详细功能介绍:1.最新产品-提供最新产品发布管理修改,和最新产品订单查看2.推荐产
- 确保表上有
UNIQUE索引或PRIMARY KEY,否则ON DUPLICATE KEY UPDATE不生效 - 更新字段不能是被冲突索引覆盖的列(比如冲突靠
email,就别在UPDATE里改email) - 慎用
VALUES(col)函数——它取的是本次 INSERT 的值,不是“原值”,容易覆盖预期外的数据
REPLACE INTO 的隐式删除风险在哪
REPLACE INTO 不是“替换”,而是“删 + 插”:先按主键/唯一键定位并 DELETE 原行,再 INSERT 新行。这会触发 DELETE 触发器、影响外键级联、重置自增 ID、丢失未显式指定的字段默认值。
常见错误现象:插入后发现 created_at 变成当前时间、status 被重置为 NULL、关联子表记录被意外 CASCADE 删除。
性能影响:DELETE + INSERT 比 ON DUPLICATE KEY UPDATE 多一次索引查找和日志写入,QPS 高时延迟明显上升。
实操建议:
- 除非明确需要清空旧行再重建(比如全量同步配置表),否则一律用
INSERT ... ON DUPLICATE KEY UPDATE - 检查表是否有
ON DELETE CASCADE外键,REPLACE INTO会激活它 - 用
EXPLAIN FORMAT=TRADITIONAL看执行计划,确认没走全表扫描(说明缺失唯一索引)
事务中混合 INSERT/UPDATE 时如何避免死锁
死锁常发生在多个事务以不同顺序访问相同几行。比如事务 A 先更新 ID=100 再插入 ID=200,事务 B 反过来先插 200 再更 100 —— 双方卡住等待对方释放锁。
使用场景:批量导入用户数据时,部分已存在需更新字段(如积分),部分新增;或订单拆单后统一落库。
实操建议:
- 所有 DML 操作按主键升序排列后再执行(例如先处理
id=1,3,5,再处理id=2,4,6),强制访问顺序一致 - 用
SELECT ... FOR UPDATE预占锁时,务必按主键排序加锁,且锁范围要覆盖后续 INSERT/UPDATE 涉及的所有行 - 避免在事务里调用外部服务(如 HTTP 请求),拉长事务时间,放大死锁概率
INSERT IGNORE 在什么情况下会静默丢数据
INSERT IGNORE 遇到重复键、NULL 插入非空列、数据截断等错误时,直接跳过整行,不报错也不提示——看起来“成功”,实际数据没进去。
常见错误现象:日志显示“Inserted 100 rows”,但查表只有 87 行;或者 updated_at 字段始终没变,以为更新了,其实是被 IGNORE 掉了。
兼容性注意:MySQL 8.0.19+ 对 INSERT IGNORE 的警告行为更严格,某些隐式类型转换也会触发 IGNORE,而老版本可能不触发。
实操建议:
- 永远不要依赖
INSERT IGNORE做“存在则跳过”的逻辑,它无法区分是键冲突还是其他错误(比如字段超长) - 用
INSERT ... ON DUPLICATE KEY UPDATE显式控制冲突行为,哪怕只是UPDATE id = id来确保行存在 - 上线前在测试库开
sql_mode=STRICT_TRANS_TABLES,让截断、零日期等错误浮出水面
真正难的不是语法,是搞清每一行 SQL 在隔离级别、索引结构、锁粒度下的真实行为。很多人调通了就提交,但线上一并发,ON DUPLICATE KEY UPDATE 的锁范围、REPLACE INTO 的触发器链、甚至 INSERT IGNORE 的警告抑制,都会变成黑盒里的定时器。









