0

0

mysql死锁是什么_mysql并发控制原理

P粉602998670

P粉602998670

发布时间:2026-01-18 08:58:02

|

737人浏览过

|

来源于php中文网

原创

MySQL死锁是事务间循环等待锁时InnoDB主动回滚一个事务的正常保护机制,非系统崩溃;通过SHOW ENGINE INNODB STATUS可查看最近一次死锁详情,包括事务ID、持有锁、等待锁及被回滚事务。

mysql死锁是什么_mysql并发控制原理

MySQL死锁不是“卡了”,而是两个或多个事务**各自拿着对方要的锁、又不肯先放**,系统检测到循环等待后主动挑一个事务回滚(报错 ERROR 1213 (40001): Deadlock found when trying to get lock),这不是崩溃,是 InnoDB 的正常保护机制。

死锁怎么一眼看出来?查 SHOW ENGINE INNODB STATUS 最直接

它会输出最近一次死锁的完整现场,关键信息包括:

  • *** (1) TRANSACTION*** (2) TRANSACTION:两个冲突事务的 ID、状态、SQL 语句
  • HOLDS THE LOCK(S):谁持有什么锁(比如 lock_mode X locks rec but not gap 表示行排他锁)
  • WAITING FOR THIS LOCK TO BE GRANTED:谁在等哪一把锁,等的是谁持有的
  • 最后还会标出「WE ROLL BACK TRANSACTION (1)」——说明哪个被牺牲了

注意:SHOW ENGINE INNODB STATUS 只保留最后一次死锁,高频死锁需配合错误日志(log_error_verbosity = 3)和监控采集。

为什么加锁顺序不一致就必死锁?InnoDB 的锁兼容性是硬约束

InnoDB 行锁本质是基于索引记录的,而锁是否冲突,取决于「锁类型 + 锁对象 + 事务隔离级别」。最典型场景:

-- 事务 A(按 id 升序加锁)
START TRANSACTION;
SELECT * FROM orders WHERE id IN (10, 20) FOR UPDATE;

-- 事务 B(按 id 降序加锁,实际执行时 MySQL 仍会排序,但若逻辑上分步加锁就危险) START TRANSACTION; SELECT FROM orders WHERE id = 20 FOR UPDATE; SELECT FROM orders WHERE id = 10 FOR UPDATE;

这时 A 持有 10 → 等 20,B 持有 20 → 等 10,循环等待成立。根本原因不是“没排序”,而是**不同事务对同一组资源请求锁的路径不收敛**。

真正安全的做法是:所有业务统一按主键/索引字段升序(或固定规则)一次性锁定全部目标行,例如始终用 WHERE id IN (10, 20) FOR UPDATE,让 MySQL 内部按索引顺序加锁,避免人为制造交叉。

innodb_lock_wait_timeout 不是防死锁的,别配错

这个参数控制的是「锁等待超时」,单位秒,默认 50。它解决的是**长时间锁等待**(比如某事务卡住不提交),不是死锁。死锁检测是毫秒级的、完全独立的机制,由 InnoDB 自动触发,不受该参数影响。

Figstack
Figstack

一个基于 Web 的AI代码伴侣工具,可以帮助跨不同编程语言管理和解释代码。

下载

常见误操作:

  • innodb_lock_wait_timeout 设成 1 秒,以为能“快速失败避开死锁”——错,死锁仍会发生,只是你看到的错误从 Deadlock found 变成了 Lock wait timeout exceeded
  • 设得过大(如 300 秒),导致阻塞堆积,掩盖真实瓶颈

建议值:线上业务保持默认 50;高并发短事务可调至 10~30,但必须配合应用层重试逻辑(尤其是捕获 ERROR 1213 后重试)。

间隙锁(Gap Lock)和 Next-Key Lock 是隐藏杀手

在 RR 隔离级别下,InnoDB 对范围查询(如 WHERE age BETWEEN 20 AND 30)会加 next-key lock(行锁 + 前面间隙锁)。这意味着:

  • 即使两事务更新不同行,只要它们扫描的索引范围有重叠,就可能互相锁住彼此无法插入的“间隙”
  • 唯一索引上的等值查询(WHERE id = 100)只加行锁,不加间隙锁;但非唯一索引或范围查询,极易触发间隙锁竞争
  • 死锁日志里出现 lock_mode X locks gap before rec 就是典型间隙锁冲突

排查时重点看 WHERE 条件是否命中了非唯一索引、是否用了范围、是否缺少覆盖索引——这些都会扩大锁范围,增加死锁概率。

死锁不是配置调参能根治的问题,它是并发逻辑与数据访问模式的映射结果。最容易被忽略的一点:**应用层事务边界是否合理?一个本该 200ms 完成的库存扣减,如果裹着 HTTP 调用、远程日志、复杂校验,锁持有时间拉长到 2 秒,那再好的 SQL 也扛不住并发压测。**

相关专题

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

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

680

2023.10.12

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

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

320

2023.10.27

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

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

347

2024.02.23

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

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

1095

2024.03.06

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

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

357

2024.03.06

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

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

676

2024.04.07

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

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

574

2024.04.29

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

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

416

2024.04.29

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

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

精品课程

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

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 797人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号