三种冲突处理是什么
写入遇到主键或唯一索引冲突时有三种处理方式:INSERT IGNORE 跳过冲突行并降级为警告;ON DUPLICATE KEY UPDATE 在冲突时更新指定列,也就是常说的 UPSERT;REPLACE 先删除旧行再插入新行。选型的关键是先明确「冲突时应该保留什么」,REPLACE 因为附带删除语义,代价常常被低估。
基本信息
| 触发条件 | 主键或唯一索引冲突 |
|---|---|
| IGNORE 行为 | 跳过并产生警告,可用 SHOW WARNINGS 查看 |
| UPSERT 行为 | 更新指定列,可写成 cnt = cnt + 1 形式 |
| REPLACE 行为 | 删除旧行再插入,触发 DELETE 与 INSERT 触发器 |
| 版本特性 | MySQL 8.0.19 起 UPSERT 支持行别名引用新值 |
典型使用场景
- 幂等写入:任务重跑时不因唯一键冲突而报错中断
- 计数器累加:UPSERT 写成 cnt 加 1,一条语句完成累加
- 配置覆盖:以配置名为唯一键,写入即覆盖最新值
- 标签去重:IGNORE 让重复标签静默跳过
- 数据同步:批量写入前先确认是否允许覆盖,避免误用 REPLACE
- 部分列更新:UPSERT 只更新变化的列,保留其他字段现状
UPsert、IGNORE 与 REPLACE
UPsert、IGNORE 与 REPLACE
INSERT INTO counters (id, cnt) VALUES (1, 1)
ON DUPLICATE KEY UPDATE cnt = cnt + 1; -- 累加
INSERT INTO counters (id, cnt) VALUES (1, 10) AS new
ON DUPLICATE KEY UPDATE cnt = new.cnt + 1; -- 8.0.19+ 行别名
INSERT IGNORE INTO tags (name) VALUES ('sql'); -- 冲突静默跳过
SHOW WARNINGS; -- 查看被跳过的原因
REPLACE INTO kv_setting (k, v) VALUES ('theme', 'dark'); -- 先删后插
SELECT id, k, v FROM kv_setting WHERE k = 'theme'; -- 核对自增 id 是否变化三种策略对照
| 策略 | 冲突行为 | 副作用 |
|---|---|---|
| INSERT IGNORE | 跳过冲突行,产生警告 | 会把数据截断等错误一并降级,掩盖问题 |
| ON DUPLICATE KEY UPDATE | 更新指定列 | 更新行数统计与预期不同,需按实际情况理解 |
| REPLACE | 删除旧行后插入新行 | 自增主键变化、触发触发器与级联删除 |
| 先查后写 | 应用层判断再决定 | 并发下有竞态,除非加锁或依赖唯一索引 |
REPLACE 会删除旧行再插入新行:自增 id 变化、触发器与级联外键都会被触发,能用 UPSERT 就别用 REPLACE。
INSERT IGNORE 会把类型转换失败、字段截断这类错误也降级成警告,问题被静默掩盖;需要严格数据校验时不要使用它。