replace into 实际执行 delete + insert,导致自增主键变更、缺失字段设默认值、触发 delete 相关逻辑;而 insert ... on duplicate key update 仅更新指定字段,保持原值、id 和关联不变,更安全可控。

REPLACE INTO 实际执行的是 DELETE + INSERT
它不是“更新”,而是先删后插。只要主键或任意唯一索引冲突,MySQL 就会定位到那条记录,执行 DELETE,再执行 INSERT。这意味着:
- 自增主键(
id)一定会变 —— 新插入的行获得新值,旧值丢失 - 如果
INSERT语句没写全字段,缺失字段会被设为默认值(如NULL或''),而不是保留原值 - 会触发
BEFORE/AFTER DELETE触发器,也可能激活外键的ON DELETE CASCADE - 需要同时具备表的
INSERT和DELETE权限
INSERT ... ON DUPLICATE KEY UPDATE 只改指定字段
它真正是“原地更新”:冲突时只执行 UPDATE 子句里明确列出的字段,其余字段、自增主键、时间戳、外键关联全部保持不变。
-
id不变,created_at不重置,updated_at = NOW()这类逻辑才可控 - 没出现在
UPDATE后面的字段,值完全不动 —— 比如只写balance = VALUES(balance),status字段不会被清空 - 不触发任何
DELETE相关逻辑,安全边界清晰 - 权限只需
INSERT和UPDATE,无需DELETE
字段缺失时的行为差异最易踩坑
这是日常开发中最容易误用的地方。比如表结构含 name、email、avatar_url(可为空),你只想更新 name:
-
REPLACE INTO user(id, name) VALUES(123, 'new_name')→email和avatar_url全被置为NULL -
INSERT INTO user(id, name) VALUES(123, 'new_name') ON DUPLICATE KEY UPDATE name = VALUES(name)→ 其他字段原封不动
一旦漏写字段又用了 REPLACE INTO,线上用户头像、邮箱批量消失不是危言耸听。
性能与并发影响不可忽略
两者在高并发场景下表现不同:
-
REPLACE INTO本质是两步操作,锁住的范围更大、时间更长,容易引发间隙锁争用 -
INSERT ... ON DUPLICATE KEY UPDATE是单次原子操作,在多数情况下锁粒度更小、吞吐更高 - 当存在多个唯一索引(如
email和phone都唯一)时,REPLACE INTO可能因匹配到多个冲突而意外删除多行(虽然罕见,但有风险)
真正要“有则更新、无则插入”,INSERT ... ON DUPLICATE KEY UPDATE 几乎总是更安全、更可控的选择;REPLACE INTO 仅适合你明确需要“彻底替换整行+接受 ID 变更”的极少数场景。











