如何在MySQL中正确理解锁升级与死锁产生的必要条件

轻敏同学_6276

轻敏同学_6276

2026-09-05

800人浏览

原创

mysql innodb无主动锁升级机制,所谓“行锁变表锁”实为索引失效导致全表扫描并逐行加锁,或rr级别下临键锁扩大范围所致;根本诱因包括where条件未走索引、函数/类型转换致索引失效、or连接非索引字段等。

如何在mysql中正确理解锁升级与死锁产生的必要条件

锁升级不是MySQL的显式操作,而是隐式退化行为

MySQL(InnoDB)本身没有“锁升级”这个主动命令或配置项。所谓“锁升级”,实际是当查询无法使用索引时,UPDATEDELETESELECT ... FOR UPDATE 等语句被迫对扫描范围内的所有行加锁,最终等效于锁住整张表——即行锁退化为表级效果。这不是优化器主动升级,而是因缺失索引导致的锁范围失控。

常见诱因包括:

  • WHERE 条件字段未建索引(如 UPDATE users SET status='x' WHERE age > 25,而 age 无索引)
  • 使用函数或表达式导致索引失效(如 WHERE YEAR(create_time) = 2025
  • 隐式类型转换(如 idINT,但传入字符串 '123'
  • 使用 OR 连接多个非索引字段条件

这种“伪升级”会极大增加锁冲突概率,是死锁高频前置原因。

死锁的四个必要条件在InnoDB中都有对应实现

死锁不是随机发生的异常,而是满足四个经典条件后必然出现的状态。在 InnoDB 中,它们一一具象化为:

  • 互斥条件:同一行上的 X 锁与 X 锁/ S 锁互斥;间隙锁之间也互斥(尤其在 RR 隔离级别下)
  • 持有并等待:事务 A 已持 table_a.id=1 的记录锁,同时请求 table_b.id=2 的锁;事务 B 反之
  • 不可剥夺:InnoDB 不支持强行释放其他事务持有的锁,只能靠回滚打破循环
  • 循环等待:InnoDB 的 wait-for graph 检测到 A→B→A 的环,立即触发死锁判定

注意:innodb_deadlock_detect=ON(默认开启)是检测循环等待的关键开关;关掉它,死锁不会被主动发现,只会卡在 innodb_lock_wait_timeout 后报超时错误,掩盖真实问题。

交叉更新顺序是最典型的死锁触发场景

两个事务以不同顺序访问相同资源集,是生产中最常见、最可复现的死锁来源。例如:

-- 事务1
BEGIN;
UPDATE orders SET status = 'shipped' WHERE order_id = 1001;
UPDATE users SET last_order_time = NOW() WHERE user_id = 5001;
COMMIT;
-- 事务2
BEGIN;
UPDATE users SET balance = balance - 100 WHERE user_id = 5001;
UPDATE orders SET status = 'paid' WHERE order_id = 1001;
COMMIT;

此时:

MySQL
MySQL

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

下载
  • 事务1 持有 orders 行锁,等待 users 行锁
  • 事务2 持有 users 行锁,等待 orders 行锁
  • InnoDB 检测到环形依赖,回滚其中一个事务(通常选 undo log 小的那个)

这类死锁与隔离级别无关,RC 和 RR 下都会发生;唯一可靠解法是**所有业务代码统一访问多表的顺序**(比如约定总是先 usersorders)。

间隙锁参与死锁常被忽略

在 RR 隔离级别下,WHERE 范围查询(如 id BETWEEN 10 AND 20)会触发 Gap LockNext-Key Lock,锁定索引间隙。这些锁不针对具体数据行,却能阻塞插入,也能卷入死锁。

示例:

BEGIN;
SELECT * FROM products WHERE price > 99 AND price <p>若另一事务执行:</p><pre class="brush:php;toolbar:false;">INSERT INTO products (price) VALUES (120); -- 被阻塞

而它又恰好持有某行锁并等待第一个事务释放间隙锁,就构成死锁。这种死锁日志里不会显示“行号”,只写“gap lock on index …”,排查时容易漏掉。

真正棘手的是:即使你只更新单行,只要 SQL 带了范围条件(哪怕 id > 1000),就可能带上间隙锁——这和直觉不符,却是 RR 级别的设计使然。

相关文章

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

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

下载

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

相关专题

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

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

2023.06.20

1913

6

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

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

2023.06.21

1179

5

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

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

2023.07.18

695

5

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

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

2023.07.19

2492

5

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

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

2023.07.25

4088

4

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

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

2023.08.08

979

3

sqlserver和mysql区别
sqlserver和mysql区别

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

2023.08.11

4351

4

mysql忘记密码
mysql忘记密码

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

2023.08.14

3942

7

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

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

2023.08.16

5054

11

热门下载

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

精品课程

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

共1课时 | 169人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 273人学习