MySQL中REPLACE INTO操作引发的死锁和INSERT有何不同?

阿丽酱_4895

阿丽酱_4895

2026-07-24

663人浏览

原创

replace into 在并发下极易触发死锁,因其内部执行 delete + insert 两阶段加锁且第一阶段锁不释放;而普通 insert 冲突时直接报错、锁立即释放,insert ... on duplicate key update 仅对冲突行加一次 x 锁并原地 update,死锁风险更低。

mysql中replace into操作引发的死锁和insert有何不同?

REPLACE INTO 在并发下极易触发死锁,而普通 INSERT 不会 —— 根本区别在于它内部执行的是 DELETE + INSERT 两阶段加锁,且第一阶段的锁不释放。

REPLACE INTO 的加锁流程导致死锁风险升高

普通 INSERT 只尝试插入一行,冲突时直接报错退出,锁在事务回滚或提交后立即释放;而 REPLACE INTO 遇到唯一键冲突时,会先对冲突行加 X 锁(用于后续 DELETE),再尝试插入新行 —— 这个过程中,DELETE 阶段持有的锁不会释放,直到整个语句完成。两个并发 REPLACE INTO 同时命中同一唯一值(比如都写 b = 8),就可能互相等待对方释放 next-key lock 和 insert intention lock,形成循环等待。

  • 单次 REPLACE INTO 实际执行:先 INSERT → 失败 → 加锁定位冲突行 → DELETE → INSERT 新行
  • DELETE 阶段获取的 X 锁(如 8, 100 next-key X lock)在整个语句结束前一直持有
  • 第二个并发事务在同样位置尝试 INSERT 时,会申请 insert intention lock,但被第一个事务的 X 锁阻塞
  • 若此时第一个事务又试图插入另一行(或被调度顺序颠倒),就满足死锁四要素

INSERT ... ON DUPLICATE KEY UPDATE 更安全,但不是完全无锁

INSERT ... ON DUPLICATE KEY UPDATE 虽然也处理冲突,但它的锁行为更收敛:它只对冲突行加一次 X 锁,然后直接做原地 UPDATE,不触发 DELETE + INSERT 的两阶段锁膨胀。这意味着锁持有时间更短、范围更小,死锁概率显著低于 REPLACE INTO。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • UPDATE 操作复用原有行记录,AUTO_INCREMENT 值不跳变(除非显式更新主键)
  • 字段未出现在 UPDATE 子句中时,旧值保留;而 REPLACE INTO 缺失字段会被设为默认值
  • 即使并发写同一唯一键,只要 UPDATE 不涉及其他行或索引,通常只产生行级锁竞争,不构成死锁链

表结构决定 REPLACE INTO 是否真正“替换”

没有主键或唯一索引的表上,REPLACE INTO 等价于 INSERT,不会触发 DELETE 逻辑,自然也不会有额外死锁风险 —— 但这时它已失去“替换”意义,还可能因误用导致重复数据。

  • 仅含主键:冲突时 DELETE + INSERT,AUTO_INCREMENT 不递增
  • 仅含唯一键:冲突时 DELETE + INSERT,AUTO_INCREMENT 会 +1(新行获得新 ID)
  • 同时含主键和唯一键:冲突发生在唯一键时,AUTO_INCREMENT +1;冲突发生在主键时,ID 不变
  • 无任何唯一约束:REPLACE INTO 就是普通 INSERT,binlog 记为 INSERT_EVENT

线上环境应优先用 INSERT ... ON DUPLICATE KEY UPDATE 替代 REPLACE INTO

除非你明确需要“清空旧行所有字段再重插”(比如字段多、默认值可控、且能保证每次写全字段),否则 REPLACE INTO 的锁行为和语义副作用(字段覆写、自增值跳变、binlog 类型混杂)在高并发场景下代价过高。

  • 死锁不是偶发异常,而是可复现的并发路径 —— 用压测脚本能稳定触发
  • MySQL 8.0+ 虽修复了部分死锁日志误导(如错误显示 HOLDS THE LOCK),但底层加锁逻辑未变
  • 如果必须用 REPLACE INTO,务必确保写入字段完整,避免默认值污染;并控制并发度,或加应用层分布式锁

真正容易被忽略的点是:死锁往往不是因为“写得多”,而是因为“写得不够全”——字段缺失导致隐式默认值写入,进而引发意料之外的索引变更和锁范围扩大。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2253

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1379

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

815

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

3092

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

5248

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

1159

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5511

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

4822

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

6394

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 188人学习