• 面试官:什么是 Next-Key Lock?作用是什么?

面试官:什么是 Next-Key Lock?作用是什么?

2025-08-16 12:31:45 栏目:宝塔面板 49 阅读

Next-Key Lock 是 InnoDB 存储引擎中非常基础也是非常重要的一个锁。今天来聊一聊 Next-Key Lock。

首先我们回顾一下 MySQL 的事务隔离级别。

  • 串行化(Serializable):事务对数据读写都是串行的。
  • 可重复读(Repeatable Read):事务执行过程中,多次读取同一行数据,读取结果一致。MySQL 默认隔离级别就是可重复读。
  • 读已提交数据(Read Committed):事务执行过程中,如果有其他事务修改了数据并且提交事务,当前事务可以读取到最新提交的数据。
  • 读未提交数据(Read Uncommitted):事务执行过程中,可以读取到其他事务未提交的数据。

可重复读隔离级别解决了幻读问题,而解决的方式就是通过 MVCC 和 Next-Key Lock。

幻读:同一事务内多次查询同一范围内的数据,因其他事务插入或删除符合条件的数据,导致事务在后面读取到的结果集不一样,像产生了幻觉。

介绍

Next-Key Lock 是间隙锁(gap lock)和行锁(index-record lock)的组合。

  • 行锁: 锁定索引中的某一条具体记录。
  • 间隙锁: 锁定索引记录之间的间隙,它锁定的是一个范围,这个范围内不存在数据。例如,如果锁定了 (10, 20) 这个范围,那其他事务就不能在这个范围内插入新记录。

一个 Next-Key Lock,也就是行锁加上该行之前的间隙锁,因此,它锁定的是一个前开后闭区间。

我们假设有一张表 t,包含(id,a,b)3 个字段,其中 id 是主键,字段 a 上面有普通索引,字段 b 没有索引。建表语句如下:

CREATE TABLE `t` ( 
`id` int(10) NOT NULL, 
`a` int(10) DEFAULT NULL, 
`b` int(10) DEFAULT NULL, 
PRIMARY KEY (`id`), 
KEY `idx_a` (`a`)) ENGINE=InnoDB;

表中有 4 条记录,分别(5,5,5),(10,10,10),(15,15,15),(20,20,20),那如果执行下面语句:

select * from t where id = 7 for update;

这样会对 id= 10 的记录加 Next-Key Lock,锁定的是 (5, 10] 这个区间,也就是说,除了锁住 id = 10 这条记录(行锁),同时间隙锁锁住了 5 和 10 之间的间隙(5,10)。

而如果执行下面这条 SQL,则会对整张表加 Next-Key Lock,因为字段 c 没有索引,新插入的数据都可能包含 c = 6。加锁后,形成 5 个范围:

select * from t where c = 6 for update;

图片

加上了 Next-Key Lock,可以阻止其他事务在被锁定的间隙中插入新的记录,从而保证了当前事务中多次执行相同查询时,不会有新的记录查出来,解决了幻读问题。

在可重复隔离级别下,执行下面几个 SQL 时,都可能会对扫描过程中访问到的记录加 Next-Key Lock:

SELECT * from t where id =xxx FOR UPDATE;//id 不存在
SELECT * from t where a =xxx FOR UPDATE;
SELECT * from t where b =xxx FOR UPDATE;
SELECT * from t where id BETWEEN 10 AND 20;
SELECT * from t where id =xxx LOCK IN SHAREMODE;
UPDATE t set b = xxx where id = yyy;
DELETE from t where id = yyy;

非唯一索引和无索引的字段,都可能会匹配多条记录,所以会加 Next-Key Lock。

那如果查询的 id 存在,还会加 Next-Key Lock 吗? 比如上面的表,执行 SQL:

SELECT * from t where id = 10 for update;

答案是不会加 Next-Key Lock,这个时候 Next-Key Lock 退化成了行锁。

查询语句符合下面三个条件时,Next-Key Lock 会退化成行锁:

  1. 查询使用的是唯一索引;
  2. SQL 条件是等值匹配(比如 WHERE unique_key = X);
  3. 扫描到的记录确定存在。

如果上面 3 个条件有一个不符合 ,都会加 Next-Key Lock。

另一点,虽然 Next-Key Lock 是前开后闭区间,如果索引上等值查询向右遍历到最后一个值不满足等值条件,则退化为间隙锁。比如执行下面 SQL:

SELECT * from t where id = 8 for update;

Next-Key Lock 退化为间隙锁,加锁范围是(5,10)。id = 10 的这条记录不影响其他事务修改操作。

优缺点

优点:解决了 REPEATABLE READ 隔离级别下幻读问题,有效保证了数据一致性。

缺点: 增加了锁的粒度,一定情况下会降低并发性能,并增加死锁发生的概率。因为多个事务可能以不同的顺序请求对重叠的间隙加锁,很容易造成死锁。

下面是一个死锁的案例,事务 A 准备插入一条(8,8,8)的记录,事务 B 准备插入一条(9,9,9)的记录,其他他们相互不影响,但加了 Next-Key Lock,就容易造成死锁。

事务 A

事务 B

select * from t where id = 8 for update;



select * from t where id = 9 for update;


insert into t values(9,9,9);

insert into t values(8,8,8);


这样两个事务都会加(5,10)这个间隙锁,最终相互等待,形成死锁。

为什么两个事务都可以加上间隙锁,因为间隙锁之间不会冲突。

总结

Next-Key Lock 是 InnoDB 引擎行锁加间隙锁的组合,它锁住的是一个前开后闭的区间,消除了 REPEATABLE READ 隔离级别下的幻读问题。理解 Next-Key Lock 要把握两点:

  1. 可重复隔离级别下才会生效;
  2. 锁住一个前开后闭的区间,但一定条件下可能退化成行锁或者间隙锁。

本文地址:https://www.yitenyun.com/304.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 TIME_WAIT 运维 负载均衡 JumpServer SSL 堡垒机 跳板机 HTTPS JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 HexHub 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 服务器 管理口 HTTPS加密 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 Windows宝塔 Mysql重置密码 Oracle 处理机制 InnoDB 数据库锁 无法访问宝塔面板 开源 PostgreSQL 存储引擎 监控 连接控制 机制 Serverless 无服务器 语言 ES 协同 技术 Spring Redis 异步化 服务器性能 分页查询 索引 缓存方案 缓存架构 缓存穿透 高可用 group by Undo Log GreatSQL 连接数 SQL 动态查询 机器学习 日志文件 MIXED 3 响应模型 R2DBC SVM Embedding 优化 万能公式 R edis 线程 数据 主库 自定义序列化 RocketMQ 长轮询 配置 云原生 Netstat Linux 服务器 端口 Linux 安全 Postgres OTel Iceberg 工具 ​Redis 推荐模型 SQLark scp Linux的scp怎么用 scp上传 scp下载 scp命令 AI 助手 共享锁 PG DBA 向量数据库 大模型 openHalo 存储 SQLite-Web SQLite 数据库管理工具 Hash 字段 Recursive 电商 系统 OB 单机版 查询 Ftp 架构 • 索引 • 数据库 流量 Rsync 锁机制 修改DNS Centos7如何修改DNS redo log 重做日志 数据分类 加密 磁盘架构 sftp 服务器 参数 向量库 Milvus 线上 库存 预扣 人工智能 推荐系统 场景 聚簇 非聚簇 防火墙 黑客 业务 同城 双活 信息化 智能运维 MySQL 9.3 Python 高效统计 今天这篇文章就跟大家 Doris SeaTunnel MVCC 传统数据库 向量化 不宕机 数据备份 mini-redis INCR指令 RDB AOF 网络架构 网络配置 INSERT COMPACT 缓存 分库 分表 Redisson 锁芯 prometheus Alert 窗口 函数 PostGIS 启动故障 事务 Java 开发 Canal Web 崖山 新版本 filelock MongoDB 数据结构 IT运维 B+Tree ID 字段 分布式 集中式 ZODB 核心架构 订阅机制 引擎 性能 数据脱敏 加密算法 Go 数据库迁移 数据类型 虚拟服务器 虚拟机 内存 读写 容器 DBMS 管理系统 频繁 Codis 模型 Redis 8.0 容器化 网络故障 OAuth2 Token JOIN QPS 高并发 微软 SQL Server AI功能 Pottery 聚簇索引 非聚簇索引 原子性 发件箱模式 自动重启 部署 Entity 工具链 国产数据库 SpringAI Testcloud 云端自动化 速度 服务器中毒 事务隔离 分页方案 排版 排行榜 排序 SSH Caffeine CP Web 接口 数据页 数据集成工具 MCP 开放协议 行业 趋势 悲观锁 乐观锁 StarRocks 数据仓库 Redka sqlmock LRU 大表 业务场景 1 分页 AIOPS 分布式架构 分布式锁​ dbt 数据转换工具 优化器 池化技术 连接池 单点故障 仪表盘 网络 Order EasyExcel MySQL8 意向锁 记录锁 InfluxDB 事务同步 日志 IT 字典 RAG HelixDB 对象 双引擎 播客 订单 单线程 Crash 代码 主从复制 代理 编程 UUIDv7 主键 Ansible LLM UUID ID 语句 Valkey Valkey8.0 恢复数据 Pump ReadView 线程安全 数据字典 兼容性 产业链 List 类型 Weaviate MGR 分布式集群 失效 解锁 调优 Next-Key 表空间 分布式锁 Zookeeper 慢SQL优化 关系数据库 GitHub Git 矢量存储 数据库类型 AI代理 查询规划 RR 互联网 国产 用户 算法 千万级 快照读 当前读 视图 神经系统 count(*) count(主键) 行数 CAS 技巧 多线程 并发控制 恢复机制 拦截器 动态代理 闪回