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

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

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

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