导读:本期聚焦于小伙伴创作的《MySQL锁机制全解析:从全局锁到临键锁,彻底掌握并发控制原理》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《MySQL锁机制全解析:从全局锁到临键锁,彻底掌握并发控制原理》有用,将其分享出去将是对创作者最好的鼓励。

MySQL锁机制全解析:从全局锁到临键锁,彻底掌握并发控制原理

MySQL全局锁、表锁、行锁、间隙锁、临键锁超详细讲解

在数据库并发访问的场景中,锁机制是保证数据一致性和完整性的核心。MySQL中的锁机制层层递进,从全局到表级再到行级,不同粒度的锁适用于不同的业务场景。本文将从宏观到微观,详细剖析MySQL中的全局锁、表锁、行锁、间隙锁和临键锁,帮助你彻底搞懂MySQL的并发控制原理。

一、全局锁

全局锁是对整个数据库实例加锁,加锁后整个数据库处于只读状态,后续的所有写操作、DDL语句以及更新操作的事务提交语句都将被阻塞。

1. 使用场景

全局锁最典型的使用场景是全库逻辑备份。在备份过程中,不希望有数据变动,以保证备份的一致性。

2. 加锁与解锁方式

-- 加全局读锁
FLUSH TABLES WITH READ LOCK;
-- 释放全局锁
UNLOCK TABLES;

3. 实际备份建议

在InnoDB引擎中,进行全库备份时推荐使用 mysqldump --single-transaction 参数,它利用MVCC机制实现一致性非锁定读,不会阻塞业务的正常读写,避免使用全局锁导致数据库长时间不可写入。

mysqldump -h www.ipipp.com -u root -p --single-transaction mydb > backup.sql

二、表级锁

表级锁会锁定整张表,锁粒度大,并发度低。MySQL中的表级锁主要包含:表锁、元数据锁(MDL)和意向锁。

1. 表锁(Table Lock)

表锁分为读锁(共享锁)和写锁(排他锁)。加锁后,当前会话和其他会话对该表的读写操作均会受到限制。

-- 加读锁(当前会话可读不可写,其他会话可读不可写)
LOCK TABLES t1 READ;
-- 加写锁(当前会话可读写,其他会话不可读不可写)
LOCK TABLES t1 WRITE;
-- 释放表锁
UNLOCK TABLES;

2. 元数据锁(MDL)

MDL不需要显式使用,在访问表时自动加上。其作用是保证并发环境下表结构的一致性。当对一个表做增删改查(DML)时,加MDL读锁;当对表结构做修改(DDL)时,加MDL写锁。

注意:长事务持有MDL读锁时,如果其他会话尝试修改表结构(申请MDL写锁),会被阻塞;进而后续所有对该表的DML操作也会被阻塞,导致连接数暴增甚至打满。因此,应避免在业务高峰期执行DDL操作。

3. 意向锁(Intention Lock)

意向锁是InnoDB自动加的表级锁,主要用于快速判断表里是否有行锁。当事务打算给某行加行级共享锁(S锁)前,必须先取得表的意向共享锁(IS锁);打算加行级排他锁(X锁)前,必须先取得表的意向排他锁(IX锁)。

意向锁与行锁的兼容性规则是:意向锁之间互相兼容;但意向锁与表级的共享锁/排他锁互斥。这样,当需要加表级写锁时,只需判断表上是否存在意向锁即可,无需逐行检查是否有行锁,极大提升了加锁效率。

三、行锁

行锁是InnoDB引擎特有的锁机制(MyISAM不支持),其锁粒度最小,只锁定匹配的索引记录,并发度最高。行锁是加在索引上的,如果没有走索引,行锁会退化为表锁。

1. Record Lock(记录锁)

记录锁是单独锁住某一条索引记录。例如,通过主键索引精准匹配一条记录时,就会加记录锁。

-- Session A
BEGIN;
-- id为主键,对id=1的记录加行级排他锁
UPDATE users SET age = 20 WHERE id = 1;

-- Session B
-- 尝试修改同一条记录,会被阻塞
UPDATE users SET age = 25 WHERE id = 1;
-- 修改其他记录则正常执行
UPDATE users SET age = 30 WHERE id = 2;

2. 行锁的三大算法前提

InnoDB的行锁是通过给索引上的项加锁来实现的,这就意味着只有通过索引条件检索数据,InnoDB才使用行级锁。如果在没有索引的字段上执行更新,会导致全表扫描,从而将所有行的锁都加上,等效于表锁。

四、间隙锁

间隙锁是InnoDB在可重复读(REPEATABLE READ)隔离级别下为了解决幻读问题而引入的锁机制。它锁定的是索引记录之间的间隙(开区间),防止其他事务在间隙中插入新记录。

1. 幻读问题

在同一个事务中,先后执行相同的范围查询,后一次查询看到了前一次没有看到的记录,这就是幻读。间隙锁就是为了阻止在间隙中插入数据从而避免幻读。

2. 间隙锁的锁定逻辑

假设表中存在主键id为 1, 5, 10 的三条记录。对 id=5 的记录加锁时,不仅锁住了 id=5 这条记录,还会对 (1, 5) 和 (5, 10) 这两个间隙加间隙锁。

-- 假设表中有id=1, 5, 10的记录
-- Session A
BEGIN;
-- 对id=5加记录锁,同时会在左右两侧加间隙锁
SELECT * FROM users WHERE id = 5 FOR UPDATE;

-- Session B
-- 尝试在间隙(1,5)中插入,会被阻塞
INSERT INTO users (id, name) VALUES (3, 'test');
-- 尝试在间隙(5,10)中插入,也会被阻塞
INSERT INTO users (id, name) VALUES (8, 'test');

核心要点:间隙锁之间是不冲突的,间隙锁只与“插入意向锁”冲突。也就是说,事务A加了间隙锁,事务B也可以加间隙锁,但事务B不能在这个间隙中插入数据。

五、临键锁

临键锁是InnoDB行锁的默认算法,它是记录锁 + 间隙锁的组合,锁定的是一个左开右闭的区间。

1. 锁定范围

对于上面的记录 1, 5, 10。临键锁锁定的区间为:
(负无穷大, 1]、(1, 5]、(5, 10]、(10, 正无穷大]。

当执行 SELECT * FROM users WHERE id = 5 FOR UPDATE 时,加上的就是临键锁,它既锁住了 id=5 这条记录本身,也锁住了 (1, 5] 和 (5, 10] 的范围。

2. 退化机制

临键锁在不同场景下会退化,这是理解锁行为的关键:

  • 等值查询,记录存在:临键锁会退化为记录锁,只锁定匹配的索引记录本身,不再锁定两侧的间隙。

  • 等值查询,记录不存在:临键锁会退化为间隙锁,锁定寻找记录经过的间隙区间,不锁定任何实际记录。

  • 范围查询:会对扫描到的范围加临键锁,命中记录的向右边界可能会退化为间隙锁。

-- 假设表中存在id为1, 5, 10的记录
-- Session A
BEGIN;
-- 等值查询id=5(存在),临键锁退化为记录锁,锁住id=5
SELECT * FROM users WHERE id = 5 FOR UPDATE;

-- Session B
-- 插入id=3成功,因为间隙(1,5)没有被锁
INSERT INTO users (id, name) VALUES (3, 'test1'); 
-- 插入id=4失败,因为id=5这条记录本身被锁住
UPDATE users SET name = 'test2' WHERE id = 5; 

-----------------------------------------

-- Session A
BEGIN;
-- 等值查询id=7(不存在),临键锁退化为间隙锁,锁住(5, 10)
SELECT * FROM users WHERE id = 7 FOR UPDATE;

-- Session B
-- 插入id=6失败,在间隙(5,10)内
INSERT INTO users (id, name) VALUES (6, 'test3');
-- 插入id=15成功,不在间隙内
INSERT INTO users (id, name) VALUES (15, 'test4');

六、总结与优化建议

MySQL的锁机制层层递进:全局锁掌控全库,表锁控制整表,行锁精细到行,而间隙锁和临键锁则是为了在RR隔离级别下彻底解决幻读问题而生。在日常开发中,为减少锁冲突和死锁概率,应遵循以下原则:

  1. 合理使用索引:确保更新和删除操作走索引,避免行锁升级为表锁。

  2. 缩小事务粒度:事务不要包含过多的逻辑,尽量在完成业务操作后立即提交,减少锁持有的时间。

  3. 控制隔离级别:如果业务对幻读不敏感,可以将隔离级别降为读提交(RC),此时只会使用记录锁,不会使用间隙锁和临键锁,并发性能更好。

  4. 按固定顺序访问资源:在多个事务中操作多张表或不同行时,尽量保持相同的访问顺序,以避免死锁的产生。

MySQL锁机制行锁间隙锁临键锁可重复读隔离级别

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。