0

0

mysql中的行级锁死锁与如何避免

P粉602998670

P粉602998670

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

|

287人浏览过

|

来源于php中文网

原创

行级锁死锁是因事务间循环等待索引行锁或间隙锁导致,InnoDB自动检测并回滚代价最小事务;根本原因包括未走索引致表级锁、间隙锁/Next-Key Lock在范围查询中扩大锁定范围,预防需确保索引访问、统一更新顺序、缩小事务粒度、合理降级隔离级别。

mysql中的行级锁死锁与如何避免

行级锁死锁是怎么发生的?

MySQL 的行级锁死锁,本质是两个或多个事务互相持有对方需要的锁、又在等对方释放,形成循环等待。InnoDB 会主动检测并回滚代价最小的那个事务,报错 Deadlock found when trying to get lock —— 这不是异常崩溃,而是引擎的正常干预机制。

关键点在于:行级锁 ≠ 安全锁。它只在**走索引**时生效;一旦查询没命中索引,InnoDB 会退化为锁整张表(或大量无关行),大幅增加冲突概率。

  • 事务 A 执行 UPDATE users SET status=1 WHERE id=100id 是主键)→ 锁住第 100 行
  • 事务 B 同时执行 UPDATE users SET status=2 WHERE name='alice'name 无索引)→ InnoDB 扫全表,锁住所有行(包括第 100 行)
  • 此时 A 等 B 释放第 100 行,B 等 A 提交释放全表锁 → 死锁触发

为什么加了索引还死锁?间隙锁(Gap Lock)和 Next-Key Lock 是隐形推手

在默认隔离级别 REPEATABLE READ 下,InnoDB 不仅锁匹配的行,还会锁住「索引间隙」——防止幻读。这意味着即使你查的是唯一值,也可能锁住前后一段范围。

例如表 t 有索引 idx_age,当前数据中 age 值为 20、25、30:

UPDATE t SET name='x' WHERE age BETWEEN 22 AND 28;

这条语句会锁住 age 在 (20,25) 和 (25,30) 两个间隙,以及 25 这一行(Next-Key Lock)。如果另一个事务正尝试插入 age=23 或更新 age=25,就可能卡住甚至死锁。

  • 联合索引下更危险:WHERE a=1(只用左前缀)仍会加 Gap Lock,哪怕 a 是唯一字段
  • SELECT ... FOR UPDATEUPDATE 在范围条件、LIKE 'abc%'BETWEEN 场景下极易触发间隙锁竞争
  • 唯一索引等值查询(如 WHERE id=123)通常只锁单行,不锁间隙 —— 这是少数“安全”场景

避免死锁的四条实操铁律

死锁无法 100% 消除,但可压缩到业务可接受水平。重点不在“检测”,而在“预防设计”。

FreeTTS
FreeTTS

FreeTTS是一个免费开源的在线文本到语音生成解决方案,可以将文本转换成MP3,

下载
  • 所有写操作必须走索引:用 EXPLAIN 验证 type 字段不是 ALLindex;缺失索引的 WHERE 条件,宁可加索引,也不接受全表扫描
  • 统一访问顺序:多个事务更新多行时,强制按主键/索引升序处理。例如批量扣库存,先 ORDER BY sku_id ASC 再遍历更新,避免 A 更新 (100,200),B 更新 (200,100)
  • 事务粒度要小:把“查 → 改 → 发消息 → 记日志”拆成多个短事务;尤其避免在事务里调外部 HTTP 接口或 sleep
  • 读写分离 + 隔离级别降级:非强一致性场景,将隔离级别设为 READ COMMITTED(关闭间隙锁),配合应用层做重试逻辑

排查死锁:别只看报错,要看 SHOW ENGINE INNODB STATUS

MySQL 每次死锁后,都会把最近一次死锁详情写入引擎状态。这不是日志文件,而是内存快照,需手动抓取:

SHOW ENGINE INNODB STATUS\G

重点关注 LATEST DETECTED DEADLOCK 区块,它会明确列出:

  • 哪个事务持有哪些锁(HELD LOCKS
  • 哪个事务在等哪一行(WAITING FOR THIS LOCK TO BE GRANTED
  • 涉及的 SQL、表、索引名、事务 ID、线程 ID

注意:该命令输出只保留最后一次死锁,且不记录历史。生产环境建议搭配监控脚本定期采集,否则问题复现后就再也看不到上下文了。

最常被忽略的一点:死锁往往不是孤立事件,而是高并发下某个慢查询或缺失索引被反复触发的结果。盯着那条报错 SQL 改,不如顺着 SHOW PROFILE 或慢日志,找到它背后真正拖慢事务的元凶。

相关专题

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

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

676

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的相关内容,可以阅读本专题下面的文章。

346

2024.02.23

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

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

1094

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数据库的相关内容,可以阅读本专题下面的文章。

675

2024.04.07

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

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

571

2024.04.29

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

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

414

2024.04.29

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

78

2026.01.09

热门下载

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

精品课程

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

共48课时 | 1.7万人学习

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

共3课时 | 0.3万人学习

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

共1课时 | 785人学习

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

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