MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。

你好,我是猿java。

申明:本文基于 MySQL 8.0.30 版本,InnoDB引擎
共享锁和排他锁 文章中,我们详细分析了共享锁和排他锁在MySQL中是如何工作的,今天,我们接着分析InnoDB引擎的 3种行锁。

MySQLInnoDB引擎的行锁主要有三类:

  1. Record Lock: 记录锁,是在索引记录上加锁;
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录;
  3. Next-key LockNext-key Lock = Gap Lock + Record Lock,它锁定了一个范围(Gap Lock实现),并且锁定记录本身(Record Lock实现);

Record Lock

什么是 Record Lock?

Record Lock,记录锁,它是针对索引记录的锁,锁定的总是索引记录。在多用户数据库系统中,多个事务可能会同时尝试读取或修改同一条记录,Record Lock确保只有一个事务能在某一时刻修改该记录,其他事务只能读取,或者在写锁释放后再进行修改。

举例说明

为了更好的说明Record Lock,我们以下面的顺序执行流来进行验证:

加锁线程 sessionA 线程B sessionB 线程B sessionC
#开启事务
begin;
给user表id=1加写锁
select id from user
where id = 1 for update;
update user set name='name121'
where id = 1;
查看InnoDB监视器中记录锁数据
show engine innodb status\G
commit提交事务
record lock 被释放
被堵塞的update操作执行ok

示例执行结果如下图:
record-lock.png

通过上面的示例可以看出:

  • 事务A(sessionA)对id=1加排他锁之后产生了记录锁
  • 事务B(sessionB)对id=1update操作被阻塞了
  • 事务C(sessionC)可以查看到Record Lock

Gap Lock

什么是Gap Lock?

Gap Lock,间隙锁,它是一种行级锁,锁住两个索引记录之间的间隙,而不是实际的数据记录,由InnoDB隐式添加。

如下图:(1,3) 表示锁住记录1 和记录3 之间的间隙,这样记录2 就无法插入,间隙可能跨越单个索引值、多个索引值,甚至是空。

gap-lock-table.png

InnoDB中,间隙锁是通过索引来实现的。这意味着间隙锁只能作用于索引,而不能直接作用于非索引列。当一个事务对某个索引列上的间隙加锁时,其他事务就无法在这个间隙中插入新的记录。

举例说明

为了更好的说明Gap Lock间隙锁,我们以下面的顺序执行流来进行验证:

加锁线程 sessionA 线程B sessionB 线程C sessionC
#开启事务
begin;
加锁
select * from user
where age = 10 for share;
insert into user(id,age) values(2,20);
#查看InnoDB监视器中记录锁数据
show engine innodb status\G
commit提交事务
Gap Lock被释放
# 被堵塞的insert操作执行成功

示例执行结果如下图:
gap-lock.png

通过上面的示例执行结果可以看出:

  • 事务A(sessionA)在加共享锁的时候产生了间隙锁(Gap Lock)
  • 事务B(sessionB)对间隙中进行insert/update操作,需要先获取排他锁(X),导致阻塞
  • 事务C(sessionC)通过show engine innodb status\G指令可以查看到间隙锁的存在。

需要说明,间隙锁只是锁住间隙内部的范围,在间隙外的insert/update操作不会受影响。

Next-Key Lock

什么是Next-Key Lock?

Next-Key Lock,称为临键锁,它是Record Lock + Gap Lock的组合,用来锁定一个范围,并且锁定记录本身锁,它是一种左开右闭的范围,可以用符号表示为:(a,b]。如下图:

next-key-lock-table.png

举例说明

为了更好的说明Next-Key Lock,我们以下面的顺序执行流来进行验证:

加锁线程 sessionA 线程B sessionB 线程C sessionC 线程D sessionD
#开启事务
begin;
#加锁
select * from user
where age = 10 for share;
#获取锁失败
insert操作被堵塞
insert into
user(id,age)
values(2,20);
#update被堵塞
update user
set name='name1'
where age = 10;
#查看InnoDB监视器中记录锁数据
show engine innodb status\G
提交事务Gap Lock被释放
commit
被堵塞的insert操作执行ok #被堵塞的update操作执行成功

示例执行结果如下图:
next-key-lock.png

通过上面的示例执行结果可以看出:

  • 事务A(sessionA)在加共享锁的时候产生了间隙锁(Gap Lock)
  • 事务B(sessionB)对间隙中进行insert操作,需要先获取排他锁(X),导致阻塞。
  • 事务C(sessionC)对间隙中进行update操作,需要先获取排他锁(X),导致阻塞。
  • 事务D(sessionD)通过show engine innodb status\G指令可以查看到间隙锁的存在。需要说明的,间隙锁只是锁住间隙内部的范围,在间隙外的insert/update操作不会受影响。

总结

Record LockGap LockGap Lock 3种锁是存在MySQLInnoDB引擎的行锁,MyISAM引擎没有:

  1. Record Lock: 记录锁,是在索引记录上加锁;
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录,即(A,B)
  3. Next-key LockNext-key Lock = Gap Lock + Record Lock,它锁定了一个范围(Gap Lock实现),并且锁定记录本身(Record Lock实现),即(A,B];;

这 3种锁都是InnoDB引擎隐式添加的,目的是为了解决可重复读隔离级别下幻读的现象。

参考

InnoDB Locking官方资料

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注:猿java,持续输出硬核文章。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
14天前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
18天前
|
SQL AliSQL 关系型数据库
MYSQL的全局锁和表锁
本文介绍了MySQL中的锁机制,包括全局锁、表级锁及其应用场景。全局锁通过`Flush tables with read lock (FTWRL)`实现,主要用于全库逻辑备份,但会阻塞更新和结构变更操作。表级锁分为显式表锁(`lock tables`)和元数据锁(MDL),前者用于控制并发访问,后者自动加锁以确保读写正确性。文章还探讨了如何安全地为小表添加字段,建议通过设置DDL等待时间或使用MariaDB/AliSQL的NOWAIT/WAIT功能避免业务阻塞。这些方法有助于在高并发场景下优化数据库性能与安全性。
|
18天前
|
关系型数据库 MySQL 数据库
MySQL中有哪几类数据模型?
面向对象模型用面向对象的思维方式与方法来描述客观实体,它继承了关系数据库系统已有的优势,并且支持面向对象建模、对象存取与持久化以及代码级面向对象数据操作,是现在较为流行的新型数据模型。 任何一个数据库管理系统都是基于某种数据模型的,数据模型不同,相应的数据库管理系统就不同。
|
2月前
|
关系型数据库 MySQL Linux
在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾
以上就是在Linux环境下备份Docker中的MySQL数据并传输到其他服务器以实现数据级别的容灾的步骤。这个过程就像是一场接力赛,数据从MySQL数据库中接力棒一样传递到备份文件,再从备份文件传递到其他服务器,最后再传递回MySQL数据库。这样,即使在灾难发生时,我们也可以快速恢复数据,保证业务的正常运行。
145 28
|
26天前
|
存储 SQL 缓存
mysql数据引擎有哪些
MySQL 提供了多种存储引擎,每种引擎都有其独特的特点和适用场景。以下是一些常见的 MySQL 存储引擎及其特点:
59 0
|
4月前
|
SQL 关系型数据库 MySQL
MySQL底层概述—10.InnoDB锁机制
本文介绍了:锁概述、锁分类、全局锁实战、表级锁(偏读)实战、行级锁升级表级锁实战、间隙锁实战、临键锁实战、幻读演示和解决、行级锁(偏写)优化建议、乐观锁实战、行锁原理分析、死锁与解决方案
237 24
MySQL底层概述—10.InnoDB锁机制
|
3月前
|
存储 SQL 关系型数据库
【YashanDB知识库】MySQL迁移至崖山char类型数据自动补空格问题
**简介**:在MySQL迁移到崖山环境时,若字段类型为char(2),而应用存储的数据仅为'0'或'1',查询时崖山会自动补空格。原因是mysql的sql_mode可能启用了PAD_CHAR_TO_FULL_LENGTH模式,导致保留CHAR类型尾随空格。解决方法是与应用确认数据需求,可将崖山环境中的char类型改为varchar类型以规避补空格问题,适用于所有版本。
|
3月前
|
SQL 关系型数据库 MySQL
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB
本文探讨了在使用YMP 23.2.1.3迁移MySQL Server字符集为latin1的中文数据至YashanDB时出现乱码的问题。问题根源在于MySQL latin1字符集存放的是实际utf8编码的数据,而YMP尚未支持此类场景。文章提供了两种解决方法:一是通过DBeaver直接迁移表数据;二是将MySQL表数据转换为Insert语句后手动插入YashanDB。同时指出,这两种方法适合单张表迁移,多表迁移可能存在兼容性问题,建议对问题表单独处理。
【YashanDB知识库】字符集latin1的MySQL中文数据如何迁移到YashanDB
|
3月前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不⼀致 2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中 这种⽅案能解决1 ⽅案的问题,但是在⾼并发下性能较低,⽽且仍然会出现数据不⼀致的问题,⽐如线程1删除了 Redis缓存数据,正在更新Mysql,此时另外⼀个查询再查询,那么就会把Mysql中⽼数据⼜查到 Redis中 1. 使用MQ异步同步, 保证数据的最终一致性 我们项目中会根据业务情况 , 使用不同的方案来解决Redis和Mysql的一致性问题 : 1. 对于一些一致性要求不高的场景 , 不做处理例如 : 用户行为数据 ,
|
4月前
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
958 43

推荐镜像

更多