MySQL行锁、间隙锁和临键锁示例详解

 更新时间:2025年11月10日 09:59:59   作者:tanxinji  
InnoDB存储引擎通过行锁、间隙锁和临键锁实现MVCC和基于锁的并发控制,确保事务隔离级别和避免死锁,本文给大家介绍MySQL行锁、间隙锁和临键锁,感兴趣的朋友跟随小编一起看看吧

在MySQL中,InnoDB存储引擎实现了其自己的多版本并发控制(MVCC)机制,以及基于锁的并发控制。InnoDB使用锁来实现事务的隔离级别,其中包括行锁(Row Locks)、间隙锁(Gap Locks)和临键锁(Next-Key Locks)。这些锁的类型对于理解事务的隔离级别和避免死锁等问题非常重要。

1.行锁 (Record Lock)

锁住索引中的一条具体记录。 保证原子性:防止多个事务同时修改同一条记录
例如:SELECT * FROM t WHERE id = 10 FOR UPDATE;会在 id=10这条记录的索引上加行锁。

示例

-- 事务A
BEGIN;
SELECT * FROM users WHERE id = 10 FOR UPDATE;
-- 此时其他事务执行以下操作会被阻塞:
-- UPDATE users SET name = 'new' WHERE id = 10;
-- DELETE FROM users WHERE id = 10;

2.间隙锁(Gap Lock)

锁住索引记录之间的间隙,但不包括记录本身。唯一目的就是防止其他事务在这个间隙中插入新记录,解决幻读问题。
它是一个开区间。例如:假设表中有 id为 5, 10, 15 的记录。那么间隙锁可以锁住 (-∞, 5),(5, 10),(10, 15),(15, +∞)这些范围。

触发时机

(1)在可重复读或串行化隔离级别下。
(2)唯一索引/普通索引,等值查询,记录不存在时。

示例

表 user,其 age字段上有普通索引

事务A:
BEGIN;
SELECT * FROM user WHERE age = 25 FOR UPDATE; 
由于 age=25不存在,InnoDB 会找到 25所在的间隙,即 (20, 30)。此时,事务 A 会在 (20, 30)这个间隙上加间隙锁。
事务B:
INSERT INTO user (id, age) VALUES (10, 22); -- 阻塞。因为 22 在 (20, 30) 区间内
INSERT INTO user (id, age) VALUES (10, 28); -- 阻塞。因为 28 在 (20, 30) 区间内
INSERT INTO user (id, age) VALUES (10, 20); -- 成功。20 是已存在的记录,不在间隙锁范围内(但可能被记录锁或临键锁影响)
INSERT INTO user (id, age) VALUES (10, 30); -- 成功。30 是已存在的记录,不在间隙锁范围内
事务 B 的插入操作会被阻塞,直到事务 A 提交。这样就防止了在事务 A 中如果再次执行 SELECT ... FOR UPDATE可能会看到新插入的 age=22或 28的记录(幻读)。

3.临键锁(Next-Key Lock)

行锁 + 间隙锁。它锁住一条记录和该记录之前的间隙。它是一个左开右闭区间。临键锁是 InnoDB 默认的行锁模式
例如:对于记录 id=10,它的临键锁会锁住 (5, 10]这个区间。这意味着既不能插入 id=6的新记录(间隙被锁),也不能修改或删除 id=10的记录(记录被锁)。

示例

(1)等值查询

事务A
SELECT * FROM users WHERE age = 20 FOR UPDATE;

过程:InnoDB 通过 B+ 树找到 age=20 的记录,并给它加上临键锁。

锁定的范围:(10, 20]。

为什么不是 [20, 20]?因为临键锁的本质是锁“下一个键”之前的间隙。对于 age=20,它会锁住 (上一个记录的值, 20],即 (10, 20]。

(2)范围查询

事务A
SELECT * FROM users WHERE age BETWEEN 15 AND 25 FOR UPDATE;

找到第一条满足条件的记录,即 age=20。锁住 (10, 20]。

继续向后扫描,找到 age=30。虽然 30 不满足条件(30 > 25),但根据规则,扫描到的记录也要加锁。锁住 (20, 30]。

最终锁定的范围:(10, 20] 和 (20, 30]。这相当于锁定了整个 (10, 30] 的区间。

效果:任何试图在 age=15 到 age=30 之间插入、更新记录的操作都会被阻塞。

(3)特殊场景:唯一索引等值查询

当使用唯一索引进行等值查询并且数据存在时,InnoDB 会优化,降级为仅使用行锁。

SELECT * FROM users WHERE id = 3 FOR UPDATE;
此时,InnoDB 知道 id=3 是唯一的,不需要防止幻读,所以只会锁住 id=3 这一条记录本身,而不会加间隙锁。

相关SQL语句

-- 查看当前锁信息
SELECT * FROM information_schema.INNODB_LOCKS;
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
-- MySQL 8.0+ 性能schema锁监控
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;

到此这篇关于MySQL行锁、间隙锁和临键锁示例详解的文章就介绍到这了,更多相关mysql行锁,间隙锁和临键锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文了解mysql索引的数据结构为什么要用B+树

    一文了解mysql索引的数据结构为什么要用B+树

    这篇文章主要介绍了一文了解mysql索引的数据结构为什么用B+树,在节点中存储某段数据的首地址,并且B+树的叶子节点用了一个链表串联起来,便于范围查找,下文利用各种索引的数据结构的方法与B+树做对比,看看它的优势到底是什么,感兴趣的小伙伴可以参考一下
    2022-04-04
  • MySQL Innodb 存储结构 和 存储Null值 用法详解

    MySQL Innodb 存储结构 和 存储Null值 用法详解

    这篇文章主要介绍了MySQL Innodb 存储结构 和 存储Null值 用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • MySQL中查询当天数据中离时间点最近的数据(两种方法)

    MySQL中查询当天数据中离时间点最近的数据(两种方法)

    在 MySQL 中,你可以使用 ORDER BY 和 LIMIT 语句来查询当天数据中离指定时间最近的数据,本文给大家介绍MySQL中查询当天数据中离时间点最近的数据,感兴趣的朋友一起看看吧
    2023-12-12
  • 磁盘已满造成的mysql启动失败问题分享

    磁盘已满造成的mysql启动失败问题分享

    这篇文章主要介绍了磁盘已满造成的mysql启动失败问题分享,需要的朋友可以参考下
    2014-04-04
  • MySQL添加索引的5种常用方式总结(附实用SQL代码)

    MySQL添加索引的5种常用方式总结(附实用SQL代码)

    在MySQL中可以使用ALTER TABLE语句来为表添加索引,索引可以提高查询性能,这篇文章主要介绍了MySQL添加索引的5种常用方式,文中还附实用SQL代码,需要的朋友可以参考下
    2025-07-07
  • MySQL9.0的两种部署模式及各个版本发布的新功能

    MySQL9.0的两种部署模式及各个版本发布的新功能

    本文主要介绍了MySQL9.0的两种部署模式及各个版本发布的新功能,文中通过图文示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • MySQL创建高性能索引的全步骤

    MySQL创建高性能索引的全步骤

    这篇文章主要给大家介绍了关于MySQL创建高性能索引的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 从数据库中取出最近三十天的数据并生成柱状图

    从数据库中取出最近三十天的数据并生成柱状图

    从数据库中取出最近三十天的数据并生成柱状图的代码,需要的朋友可以参考下。
    2011-05-05
  • 一道MySQL笔试题:输出 100 以内质数(附两种主要方法)

    一道MySQL笔试题:输出 100 以内质数(附两种主要方法)

    质数又称素数,一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数,这篇文章主要介绍了MySQL笔试题之输出100以内质数的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-08-08
  • Mysql 下中文乱码的问题解决方法总结

    Mysql 下中文乱码的问题解决方法总结

    这篇文章主要介绍了Mysql 下中文乱码的问题解决方法总结的相关资料,这里提供了解决 Mysql 中文乱码问题的办法,需要的朋友可以参考下
    2016-11-11

最新评论