线上MySQL发生死锁时事务会自动回滚哪一个

夏婷小哥_3596

夏婷小哥_3596

2026-10-22

241人浏览

原创

mysql自动回滚代价最小的事务,依据是undo log条目数、已修改行数和持有锁数量,而非随机或按发起顺序选择,以实现最快恢复。

线上mysql发生死锁时事务会自动回滚哪一个

MySQL会自动回滚“代价最小”的事务,通常是持有锁数量最少、修改行数最少、事务执行时间最短的那个。

为什么不是随机选或固定选后发起的事务

InnoDB的死锁检测器(innodb_deadlock_detect)在识别出循环等待链后,会估算每个事务的“回滚代价”(rollback cost),这个代价主要基于:

  • trx_rows_locked:当前事务已持有的行锁数量
  • trx_rows_modified:已修改但未提交的行数
  • trx_undo_log_entries:undo log条目数(反映回滚工作量)

代价越小,回滚越快,系统恢复越早。所以它不是按“谁后开始”或“谁先等”来判,而是看谁“撤得最省力”。你在线上看到日志里被回滚的事务,常常是那个只更新了一行就去等另一行锁的轻量操作,而不是那个刚批量插入了200条记录的大事务。

如何从SHOW ENGINE INNODB STATUS里确认谁被回滚了

执行SHOW ENGINE INNODB STATUS\G后,在LATEST DETECTED DEADLOCK区块中:

  • 被回滚的事务会明确标为*** (1) TRANSACTION:或*** (2) TRANSACTION:,紧接着一行写ROLLING BACK
  • 另一方事务状态是WAITING FOR THIS LOCK TO BE GRANTED
  • 注意看undo log entries字段值——被回滚的那个通常明显更小

示例片段:

MySQL
MySQL

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

下载
*** (1) TRANSACTION:
TRANSACTION 123456789, ACTIVE 2 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 1024 n bits 72 index PRIMARY of table `db`.`t` trx id 123456789 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 123456788, ACTIVE 3 sec
2 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
ROLLING BACK

应用层不能依赖“总是回滚对方”

很多业务代码默认写成“捕获Deadlock found when trying to get lock就重试”,这没问题;但如果你在事务里混用了存储过程、触发器或XA事务,回滚行为可能偏离预期:

  • 存储过程中发生的死锁,回滚的是整个外部事务,不是仅存储过程内部
  • 如果事务已显式执行过SAVEPOINT,InnoDB仍会回滚到事务起点,不尊重保存点
  • Spring @Transactional若配置了rollbackFor = Exception.class但没捕获死锁异常并重新抛出,会导致部分语句被回滚、后续语句仍在同一事务上下文中继续执行(即“半提交”现象)

这种非原子性表现,比死锁本身更难排查。

innodb_deadlock_detect关闭后会发生什么

该参数默认为ON。如果误设为OFF(极少数高并发写场景有人尝试关闭以降低开销):

  • 死锁不会被主动检测,事务将无限期等待,直到触发innodb_lock_wait_timeout(默认50秒)
  • 超时后报错Lock wait timeout exceeded,而非Deadlock found
  • 此时没有“自动选一个回滚”,而是所有卡住的事务都等满timeout才陆续失败

所以线上严禁关闭innodb_deadlock_detect——它不是性能瓶颈,而是死锁问题可被快速终结的前提。

真正容易被忽略的点在于:死锁回滚是InnoDB单边决定的,应用层看不到“正在被选为牺牲者”的中间态;你只能通过日志确认结果,而无法干预选择逻辑。这意味着所有关键业务路径必须把死锁当作常态错误来重试,且重试前要确保幂等或状态可校验。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4423

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

931

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1169

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6381

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3183

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6340

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

8641

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1170

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1032

5

热门下载

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

精品课程

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

共1课时 | 189人学习