深入解析MySQL InnoDB锁机制 - 教程

news/2025/9/26 20:10:41/文章来源:https://www.cnblogs.com/tlnshuju/p/19114169

深入解析MySQL InnoDB锁机制 - 教程

2025-09-26 20:07  tlnshuju  阅读(0)  评论(0)    收藏  举报

这段文档是 MySQL InnoDB 存储引擎中关于锁机制(InnoDB Locking)的权威详解,内容非常核心和深入。它解释了 InnoDB 如何通过多种类型的锁来实现并发控制、数据一致性、避免幻读与死锁

我们将用通俗语言 + 图解思维 + 实际例子,帮你彻底理解每一个锁类型及其作用。


总体目标:InnoDB 为什么要搞这么多锁?

  • 多个事务同时操作数据库时,必须防止:
    • 数据被乱改(丢失更新)
    • 读到不一致的数据(脏读、不可重复读、幻读)
    • 死锁导致系统卡住
  • 所以 InnoDB 设计了一套精细的锁定机制,在性能一致性之间取得平衡。

一、两大基础锁:共享锁(S)和排他锁(X)

这是所有锁的“起点”。

锁类型名称能做什么?
S 锁Shared Lock(共享锁 / 读锁)持有者可以读数据
X 锁Exclusive Lock(排他锁 / 写锁)持有者可以修改或删除数据

✅ 规则:

  1. 多个事务可以同时持有 S 锁 → 多人可读
  2. 只要有 X 锁存在,别人就不能加任何锁(S 或 X)
  3. 只要有 S 锁存在,别人可以加 S 锁,但不能加 X 锁

类比:图书馆里一本书

哪些语句会加这些锁?

SQL 语句加的锁
SELECT ...不加锁(MVCC 读历史版本)
SELECT ... FOR SHARES 锁
SELECT ... FOR UPDATEX 锁
UPDATE, DELETE自动加 X 锁
INSERT插入前加 insert intention lock(见下文)

️ 二、意向锁(Intention Locks)—— 表级“预告”锁

❓ 问题来了:

如果事务 A 正在修改某一行(加了 X 锁),这时事务 B 想对整张表加锁(如 LOCK TABLES t WRITE),怎么办?

→ 必须知道“有没有人正在用这表里的行”!

但逐行检查太慢了!于是有了 意向锁(Intention Locks)

✅ 意向锁的作用:

意向锁含义
IS意向共享锁:我要给某些行加 S 锁
IX意向排他锁:我要给某些行加 X 锁

✅ 使用规则:

  • 要加 S 锁 → 先获得 IS 或更强的锁(如 IX)
  • 要加 X 锁 → 必须先获得 IX 锁

意向锁兼容性矩阵(重点!)

XIXSIS
X
IX
S
IS

✅ = 可以共存,❌ = 冲突

关键点

示例:

-- 事务A
START TRANSACTION;
SELECT * FROM t WHERE id=1 FOR UPDATE;
-- 加 X 锁 → 自动在表上加 IX 锁
-- 此时另一个事务想 LOCK TABLE t READ(S 锁)?
-- 会检查:IX 和 S 冲突吗?→ ❌ 冲突!所以等待。

三、行锁的具体实现:Record Lock、Gap Lock、Next-Key Lock

1. Record Lock(记录锁)

✅ 示例:

SELECT * FROM t WHERE id=10 FOR UPDATE;
-- 对 id=10 的索引记录加 X 锁(record lock)

⚠️ 即使表没有主键,InnoDB 也会创建隐藏的聚簇索引,所以总是有“索引记录”可锁。


2. Gap Lock(间隙锁)

  • 锁住两个索引值之间的“空隙”
  • 目的:防止其他事务在这个“空隙”插入新记录 → 防止幻读

✅ 示例:

SELECT * FROM t WHERE age BETWEEN 20 AND 30 FOR UPDATE;
-- 不仅锁住 age=20~30 的记录
-- 还锁住 (20,30) 这个“范围”,别人不能插入 age=25 的记录

关键特性:

  • Gap Lock 不互斥!
    • 事务 A 可以在 gap 上加 S-gap 锁
    • 事务 B 也可以在同一 gap 加 X-gap 锁
  • 因为 gap 锁只是“防止插入”,不是保护数据内容
  • 当记录被删除时,多个 gap 锁需要合并,所以允许共存

何时不用 Gap Lock?


3. Next-Key Lock = Record Lock + Gap Lock

  • 锁住记录本身 + 前面的间隙
  • 是 InnoDB 在 REPEATABLE READ 隔离级别下的默认锁机制
  • 目的:完全防止幻读

✅ 示例:
假设索引有值:10, 11, 13, 20

Next-Key Lock 覆盖的区间是:

(-∞, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +∞)

每个区间都是左开右闭:(a, b] 表示不包含 a,包含 b

特别说明最后一个区间 (20, +∞)

  • 实际上是一个叫 supremum 的虚拟记录
  • 锁住“最大值之后的所有空间”

效果:

  • 任何想插入 age=25 的操作都会被阻塞
  • 实现了“可重复读”下的范围查询一致性

四、Insert Intention Lock(插入意向锁)

❓ 问题:

多个事务都想往同一个“间隙”插入数据,但位置不同,应该阻塞吗?

比如:

  • 事务 A 想插 id=5
  • 事务 B 想插 id=6
  • 当前只有 id=4id=7

→ 他们其实不冲突,应该允许并发插入!

✅ Insert Intention Lock 就是为此设计的:

工作流程:

  1. 事务要插入 → 先在 gap 上加 insert intention lock
  2. 然后尝试获取该行的 X 锁(record lock)
  3. 如果 gap 被别人用 X 锁锁住了(比如 FOR UPDATE 范围查询),则等待

示例:

-- 表中有 id=4 和 id=7
-- 事务A
INSERT INTO t(id) VALUES (5);
-- 在 (4,7) 加 insert intention lock → 成功
-- 事务B
INSERT INTO t(id) VALUES (6);
-- 同样在 (4,7) 加 insert intention lock → 也成功!
-- 因为 5≠6,不冲突

但如果:

-- 事务C
SELECT * FROM t WHERE id BETWEEN 4 AND 7 FOR UPDATE;
-- 加了 next-key lock,锁住 (4,7] 范围
-- 那么事务A/B 插入就会被阻塞

五、AUTO-INC Lock(自增锁)

❓ 问题:

多个事务同时 INSERT 到有 AUTO_INCREMENT 列的表,怎么保证 ID 不重复且连续?

✅ AUTO-INC Lock 是一种表级锁,用于保护自增值分配。

情况是否阻塞
一个事务在插入 → 其他事务插入必须等待✅ 默认行为
使用 innodb_autoinc_lock_mode=2(交错模式)❌ 不阻塞,但 ID 可能不连续

⚙️ 参数控制:

现代 MySQL 推荐使用 2,除非你需要严格连续的 ID。


六、Predicate Locks for Spatial Indexes(空间索引的谓词锁)

❓ 特殊情况:空间数据(如经纬度、地理区域)

✅ 解决方案:谓词锁(Predicate Lock)

  • 锁住一个“查询条件”本身
  • 例如:WHERE MBRContains(shape, Point(1,2))
  • InnoDB 会对这个 MBR(最小包围矩形)加锁
  • 其他事务不能插入或修改满足该条件的行

这是一种更高级的逻辑锁,确保空间查询的一致性。


✅ 总结:一张表看懂所有锁

锁类型级别用途是否阻塞其他操作
S/X Lock行级读/写锁定具体行是(X 锁最强)
IS/IX表级预告要加行锁不阻塞行操作
Record Lock行级锁具体索引记录阻塞对该记录的修改
Gap Lock行级锁间隙,防插入阻塞插入该范围
Next-Key Lock行级record + gap,防幻读强一致性保障
Insert Intention行级插入前声明意图不同位置可并发
AUTO-INC表级保护自增列可能阻塞并发插入
Predicate Lock逻辑级空间查询一致性特殊场景使用

实际建议

场景建议
普通查询SELECT(MVCC,无锁)
先查后改SELECT ... FOR UPDATE
防止幻读REPEATABLE READ + 范围查询自动加 next-key lock
高并发插入设置 innodb_autoinc_lock_mode=2
减少死锁所有事务按相同顺序操作表
查锁信息SHOW ENGINE INNODB STATUS

一句话总结

InnoDB 通过 S/X 锁 + 意向锁 + 记录锁 + 间隙锁 + 插入意向锁 的组合,在行级精细控制并发,既保证数据一致性(防止脏读、幻读),又尽可能提升并发性能。理解这些锁,是掌握 MySQL 高并发能力的关键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

根号

一. 根号分治 精髓就是拼接两个暴力 1. 余数根号分治:Remainder Problem 首先直接单点更新O(1),查询暴力跳O(n)。这个暴力的有点在于当查询的x比较大的时候,那么跳的次数就比较少。 另一种暴力思路就是维护c[i][j]为…

如何在 CentOS 7 上安装 bzip2-libs-1.0.6-13.el7.x86_64.rpm 文件

如何在 CentOS 7 上安装 bzip2-libs-1.0.6-13.el7.x86_64.rpm 文件​bzip2-libs 是 bzip2 压缩工具所需的库文件,很多软件运行时都依赖它。如果你在安装某些程序时提示缺少这个包,按本教程操作即可完成安装。 一、准…

做网站第一步区块链 做网站

开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别 https://www.geek-workshop.com/thread-1860-1-1.htmlliamjeal电梯直达1# 发表于 2012-9-10 13:41:43 | 只看该作者 |只看大图 因CooCox用户数及影响力越来越大,CooCox团队也逐渐提高了对软件及代码协议的重…

外贸网站 球衣网站查询系统

文章目录 九九乘法表打印三角形改进:控制行数的三角形有空格的三角形 九九乘法表 package com.zhang; /* 打印九九乘法表*/ public class Test8 {public static void main(String[] args) {//i是竖着的 j是横着的for (int i 1; i < 9; i) {for(int j 1; j < 9; j) {i…

建设网站收集加工素材教案鹤壁做网站公司

使用xpath定位元素时&#xff0c;有时候担心元素位置会变&#xff0c;可以考虑使用文本内容来定位的方式。 例如图中的【股市】按钮&#xff0c;只有按钮文本没变&#xff0c;即使位置变化也可以定位到该元素。 xpath内容样例&#xff1a; # 文本内容完全匹配 //button[text(…

【A】杂题选将

P13617 [ICPC 2024 APC] Bit Counting Sequence 考虑进 1 位导致位数和减 1,那么我们找到进位最多的那一次,那么他应该是形如 111..000..0 的一个东西,然后你去判定一下就好了。

有一个[1,5]的等概率随机函数fx(),在不改变fx()函数的情况下,利用fx()函数做出一个[1,7]的等概率随机函数。

有一个[1,5]的等概率随机函数fx(),在不改变fx()函数的情况下,利用fx()函数做出一个[1,7]的等概率随机函数。题目解析首先需要将fx函数转化为一个0,1的等概率的心函数 对要转换的函数的范围分析 通过0,1等概率函数利…

WSL2 磁盘清理

首先清理 apt, snap, 各个包管理器的缓存和系统日志。 然后使用 du 或 ncdu 查看磁盘空间占用,继续清理。 等到释放了空间后,再去重置 vhdx 文件大小。 重置 vhdx 文件大小 以下路径中的用户名和包名请自行修改。 se…

洛阳市做网站的wordpress百度地图使用方法

1.2.6 嵌套表AS TABLE OF嵌套表是表中之表&#xff0c;一个嵌套表是某些行的集合&#xff0c;它在主表中表示为其中的一列。对主表中的每一条记录&#xff0c;嵌套表可以包含多个行。语法如下&#xff1a;CREATE OR REPLACE TYPE table_name AS TABLE OF type;语法说明&#x…

完整教程:1.DHCP服务器

完整教程:1.DHCP服务器pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

关于OneBot的QQ机器人探索2

一个QQ聊天机器人,按照OneBot v11协议进行开发 目前实现的主要功能有: - echo 消息回显 - 搜索歌曲并发送音乐卡片 - AI聊天,概率性主动回复,支持在QQ中使用指令切换AI模型和提示词 - bing每日一图获取并发送 - 群…

一个网站怎样做两个后台网站建设软件培训学校

文章目录 前言1. 安装docker与docker-compose2. 启动容器运行镜像3. 本地访问测试4.安装内网穿透5. 创建公网地址6. 创建固定公网地址 前言 今天和大家分享一款在G站获得了26K的强大的开源在线协作笔记软件&#xff0c;Trilium Notes的中文版如何在Linux环境使用docker本地部署…

德阳网站设计网站 流程优化

如果经常在远程服务器或嵌入式设备中操作图片&#xff0c;要查看图片效果&#xff0c;就要先把图片dump到本地&#xff0c;比较麻烦。可以使用这个工具&#xff0c;直接在终端上显示。类似于这种效果。 imgcat 是一个终端工具&#xff0c;使用 iTerm2 内置的特性&#xff0c;允…

putty

https://www.cnblogs.com/zeoHere/p/18845009

深入解析:PHP 8.0+ 高级特性深度探索:架构设计与性能优化

深入解析:PHP 8.0+ 高级特性深度探索:架构设计与性能优化pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

网站前后台代码诺亚人力资源外包网

vue 悬浮球(带自动吸附功能)_vue悬浮球-CSDN博客

Django 搭配数据库开发智慧园区系统全攻略 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网站白名单查询网页制作培训有前途吗

PostgreSQL 中文社区 PL/pgSQL 是 PostgreSQL 中的一种存储过程语言&#xff0c;它支持许多常用的函数和操作符。下面列举了一些常用的 PL/pgSQL 函数和操作符&#xff1a; 1. 常用函数&#xff1a; RAISE&#xff1a;用于在存储过程中抛出异常。 RAISE EXCEPTION Error oc…

客服系统源码二次开发

我开发的客服系统后端是使用的Golang语言,Go是Google公司开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go 天生支持并发。好处太多就不多说了。 全源码客服系统用户,想要针对自己的业务,进…

喜讯!狮桥集团成为天津市行政执法监督企业联系点,共筑法治营商新环境!

近日,天津市司法局发布公告,为做好规范涉企行政执法专项行动,进一步拓宽社会力量参与行政执法监督渠道,提升行政执法监督效能,优化法治化营商环境,根据中共中央办公厅、国务院办公厅印发的《关于加强行政执法协调…