间隙锁通过锁定索引记录间的“间隙”防止其他事务插入新记录,从而避免幻读。在REPEATABLE READ隔离级别下,执行范围查询时,InnoDB不仅锁定行记录,还锁定记录之间的间隙、首记录前和末记录后的范围。例如查询id BETWEEN 10 AND 20时,会锁定(5,12)和(12,25)等间隙(假设有id为5、12、25的记录),阻止其他事务插入id在该范围内的新行。间隙锁基于B+树索引实现,影响范围可能超出预期,增加锁冲突风险。实际应用中,可通过调整隔离级别至READ COMMITTED、优化索引设计、缩小事务范围、避免不必要的锁定、监控锁状态及分批处理等方式优化间隙锁带来的并发问题。

间隙锁(Gap Lock)是InnoDB存储引擎在实现特定事务隔离级别(主要是
REPEATABLE READ
间隙锁的出现,坦白讲,是数据库设计者在追求数据一致性与并发性之间找到的一个平衡点。当我们的事务需要确保在某个数据范围内,不会有新的数据凭空出现或消失时,间隙锁就发挥了它的作用。它解决了这样一个痛点:即便我们已经锁定了查询到的所有行记录,但在并发环境下,如果其他事务在这个范围里插入了新行,我们的后续查询依然会“看到”这些新行,这就是幻读。间隙锁正是为了弥补这种“空隙”而生的。
要理解间隙锁如何避免幻读,我们得先搞清楚幻读到底是什么。想象一下,你在一个银行系统里,先查询了所有余额在100到200之间的账户。如果此时,另一个柜员恰好新开了一个账户,余额是150,并提交了。那么当你再次查询同样范围的账户时,你会发现多了一个之前没见过的账户。这就是幻读,你的事务在逻辑上认为的“不变”被打破了。
间隙锁正是为了防止这种情况发生。当一个事务在
REPEATABLE READ
SELECT ... WHERE id BETWEEN 10 AND 20 FOR UPDATE;
id
具体来说,如果你的表里有
id
id BETWEEN 10 AND 20
(5, 12)
id
(12, 25)
id
id > 10
(10, 12)
(12, 25)
(25, +∞)
这样一来,无论其他事务尝试在
(5, 12)
(12, 25)
间隙锁的工作原理,说白了,就是InnoDB利用了B+树索引的特性。它不是在内存中画一个“锁定的区域”,而是通过在索引结构中的特定位置设置锁标记来实现的。当一个事务需要锁定某个范围时,InnoDB会找到这个范围的起始和结束索引键值,然后锁定这些键值所代表的记录以及它们之间的“空隙”。值得注意的是,间隙锁是作用于索引的,所以一个高效的索引设计对于间隙锁的性能至关重要。
间隙锁的影响范围,有时候会超出我们的预期,这正是它可能导致死锁和并发问题的原因。它会锁定:
举个例子,假设我们有一个
users
id
id = 1, 5, 10, 15
SELECT * FROM users WHERE id > 7 AND id < 12 FOR UPDATE;
id=10
(5, 10)
(10, 15)
id
理解间隙锁的机制,对于编写高性能、无死锁的SQL至关重要。在实际应用中,我们经常会遇到因为间隙锁导致的并发问题,比如死锁或者事务长时间等待。
何时触发间隙锁?
REPEATABLE READ
WHERE col > X AND col < Y
WHERE col LIKE 'prefix%'
SELECT * FROM users WHERE status = 'pending' FOR UPDATE;
status
pending
INSERT
优化策略:
READ COMMITTED
READ COMMITTED
FOR UPDATE
LOCK IN SHARE MODE
SHOW ENGINE INNODB STATUS
LATEST DETECTED DEADLOCK
间隙锁是一个强大的工具,它在保证数据一致性方面功不可没,但同时它也是一把双刃剑,不恰当的使用或不理解其工作原理,很容易导致性能瓶颈。所以,深入理解它,并结合业务场景进行优化,是我们每个开发者都需要掌握的技能。
以上就是什么是间隙锁(Gap Lock)?它解决了什么问题?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号