首页 > 数据库 >MySQL 的全局锁、表锁和行锁

MySQL 的全局锁、表锁和行锁

时间:2023-07-16 15:34:44浏览次数:36  
标签:加锁 行锁 lock 16 next 索引 key MySQL 表锁

在前一篇文章我讲了下 MySQL 的全局锁、表记锁和行级别锁,其中行级锁只提了概念,并没有具体说。

因为行级锁加锁规则比较复杂,不同的场景,加锁的形式还不同,所以这次就来好好介绍下行级锁。

对记录加锁时,加锁的基本单位是 next-key lock,它是由记录锁和间隙锁组合而成的,next-key lock 是前开后闭区间,而间隙锁是前开后开区间

但是,next-key lock 在一些场景下会退化成记录锁或间隙锁。

那到底是什么场景呢?今天,我们就以下面这个表来进行实验说明。

其中,id 是主键索引(唯一索引),b 是普通索引(非唯一索引),a 是普通的列。

注意,我的 MySQL 的版本是 8.0.26,不同版本的加锁规则可能是不同的

唯一索引等值查询

当我们用唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:

  • 当查询的记录是存在的,在用「唯一索引进行等值查询」时,next-key lock 会退化成「记录锁」

  • 当查询的记录是不存在的,在用「唯一索引进行等值查询」时,next-key lock 会退化成「间隙锁」

  1. 加锁的基本单位是 next-key lock,因此会话1的加锁范围是(8, 16];

  2. 但是由于是用唯一索引进行等值查询,且查询的记录存在,所以 next-key lock 退化成记录锁,因此最终加锁的范围是 id = 16 这一行

所以,会话 2 在修改 id=16 的记录时会被锁住,而会话 3 插入 id=9 的记录可以被正常执行。

  1. 加锁的基本单位是 next-key lock,因此主键索引 id 的加锁范围是(8, 16];

  2. 但是由于查询记录不存在,next-key lock 退化成间隙锁,因此最终加锁的范围是 (8,16)。

所以,会话 2 要往这个间隙里面插入 id=9 的记录会被锁住,但是会话 3 修改 id =16 是可以正常执行的,因为 id = 16 这条记录并没有加锁。

唯一索引范围查询

举个例子,下面这两条查询语句,查询的结果虽然是一样的,但是加锁的范围是不一样的。

select * from t_test where id=8 for update;select * from t_test where id>=8 and id<9 for update;

  1. 最开始要找的第一行是 id = 8,因此 next-key lock(4,8],但是由于 id 是唯一索引,且该记录是存在的,因此会退化成记录锁,也就是只会对 id = 8 这一行加锁;

  2. 由于是范围查找,就会继续往后找存在的记录,也就是会找到 id = 16 这一行停下来,然后加 next-key lock (8, 16],但由于 id = 16 不满足 id < 9,所以会退化成间隙锁,加锁范围变为 (8, 16)。

所以,会话 1 这时候主键索引的锁是记录锁 id=8 和间隙锁(8, 16)。

会话 2 由于往间隙锁里插入了 id = 9 的记录,所以会被锁住了,而 id = 8 是被加锁的,因此会话 3 的语句也会被阻塞。

由于 id = 16 并没有加锁,所以会话 4 是可以正常被执行。

非唯一索引等值查询

当我们用非唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:

  • 当查询的记录存在时,除了会加 next-key lock 外,还额外加间隙锁,也就是会加两把锁

  • 当查询的记录不存在时,只会加 next-key lock,然后会退化为间隙锁,也就是只会加一把锁。

  1. 先会对普通索引 b 加上 next-key lock,范围是(4,8];

  2. 然后因为是非唯一索引,且查询的记录是存在的,所以还会加上间隙锁,规则是向下遍历到第一个不符合条件的值才能停止,因此间隙锁的范围是(8,16)。

所以,会话1的普通索引 b 上共有两个锁,分别是 next-key lock (4,8] 和间隙锁 (8,16) 。

那么,当会话 2 往间隙锁里插入 id = 9 的记录就会被锁住,而会话 3 和会话 4 是因为更改了 next-key lock 范围里的记录而被锁住的。

然后因为 b = 16 这条记录没有加锁,所以会话 5 是可以正常执行的。

  1. 先会对普通索引 b 加上 next-key lock,范围是(8,16];

  2. 但是由于查询的记录是不存在的,所以不会再额外加个间隙锁,但是 next-key lock 会退化为间隙锁,最终加锁范围是 (8,16)。

会话 2 因为往间隙锁里插入了 b = 9 的记录,所以会被锁住,而 b = 16 是没有被加锁的,因此会话 3 的语句可以正常执行。

非唯一索引范围查询

非唯一索引和主键索引的范围查询的加锁也有所不同,不同之处在于普通索引范围查询,next-key lock 不会退化为间隙锁和记录锁

  1. 最开始要找的第一行是 b = 8,因此 next-key lock(4,8],但是由于 b 不是唯一索引,并不会退化成记录锁。

  2. 但是由于是范围查找,就会继续往后找存在的记录,也就是会找到 b = 16 这一行停下来,然后加 next-key lock (8, 16],因为是普通索引查询,所以并不会退化成间隙锁。

所以,会话 1 的普通索引 b 有两个 next-key lock,分别是 (4,8] 和(8, 16]。这样,你就明白为什么会话 2 、会话 3 、会话 4 的语句都会被锁住了。

总结

这次我以 MySQL 8.0.26 版本做了几个实验,让大家了解了唯一索引和非唯一索引的行级锁的加锁规则。

这里需要注意的是,不同的版本加锁规则可能会有所不同。我这里总结下, 我这个 MySQL 版本的行级锁的加锁规则。

  • 当查询的记录是存在的,next-key lock 会退化成「记录锁」。

  • 当查询的记录是不存在的,next-key lock 会退化成「间隙锁」。

  • 当查询的记录存在时,除了会加 next-key lock 外,还额外加间隙锁,也就是会加两把锁。

  • 当查询的记录不存在时,只会加 next-key lock,然后会退化为间隙锁,也就是只会加一把锁。

非唯一索引和主键索引的范围查询的加锁规则不同之处在于:

  • 唯一索引在满足一些条件的时候,next-key lock 退化为间隙锁和记录锁。

  • 非唯一索引范围查询,next-key lock 不会退化为间隙锁和记录锁。

这些加锁规则其实很好总结的,大家自己可以用我文中的案例测试一遍,看一下你的 MySQL 版本和我的 MySQL 版本的加锁规则有什么不同。

本文由mdnice多平台发布

标签:加锁,行锁,lock,16,next,索引,key,MySQL,表锁
From: https://www.cnblogs.com/wind-xwj/p/17557913.html

相关文章

  • 用python爬去电影评分保存进mysql
    用Python爬取电影评分保存进MySQL在今天的数字化时代,电影评分是人们选择观看电影的重要参考因素之一。那么,如何通过Python爬取电影评分数据,并保存到MySQL数据库中呢?本文将为你提供一种简单的方法来实现这个目标。准备工作在开始之前,我们需要确保已经安装了Python和MySQL,并且已经......
  • MySQL为什么不建议使用delete删除数据?
    这篇文章我会从InnoDB存储空间分布,delete对性能的影响,以及优化建议方面解释为什么不建议delete删除数据。InnoDB存储架构从这张图可以看到,InnoDB存储结构主要包括两部分:逻辑存储结构和物理存储结构。逻辑上是由表空间tablespace—> 段segment或者inode—>区Extent——>......
  • MySQL锁
    全局锁对数据库加锁,典型使用场景是全库备份。加全局读锁,整库只读:Flushtableswithreadlock(FTWRL)。针对全库只读,不使用setglobalreadonly=true,使用FTWRL的原因:1.readonly的值可能用来做逻辑判断,例如判断是主库还是备库。2.FTWRL在客户端异常断开连接后自动释放全局锁,re......
  • MySQL主备
    MySQL主备同步原理1备库io_thread通过长连接获取主库的binlog2备库sql_thread执行binlog节点A和B之间互为主备关系,都认为对方是主,切换时不用再修改主备关系。解决双Mbinlog循环同步问题1A更新的事务,binlog记的是A的serverid2B同步后生成的binlog的serverid也是A的serveri......
  • mysql安装
    安装方式选择:二进制、源码、yum安装(生产选择二进制安装)参考链接:https://www.cnblogs.com/yyxianren/p/11319544.html1.卸载默认安装的mariadb:  yumremovemariadb*-y2.添加mysql用户:  useradd-s/sbin/nologin-Mmysql3.解压tar文件并移动到指定目录,并赋权: ......
  • MySQL索引
    主键索引和普通索引结构上的区别每一个索引在InnoDB里面对应一棵B+树。有一个主键列为ID的表,表中有字段k,在k上有索引。CREATETABLET(  idintPRIMARYKEY,  kintNOTNULL,  namevarchar(16),  INDEX(k))ENGINE=InnoDB;表中R1~R5的(ID,k)值分别为(100,1......
  • MySQL自增值
    InnoDB引擎1自增值的保存机制MySQL5.7及之前的版本自增值保存在了内存里面,MySQL8.0版本才有自增值持久化能力(把自增值的变更记录在了redolog,重启后依靠redolog回复)。每次重启后,把自增值的最大值max(id)+1作为这个表当前的自增值。例如,一个表最大的id是10,AUTO_INCREMENT=11,删......
  • mysql主从复制
    1.MySQL主从复制介绍  主从复制实现的原理:(同步二进制日志文件)  主服务器开启二进制日志功能,当mysql进行操作同时生成一条操作事件日志,  并写入二进制日志文件中,从服务器通过同步二进制日志文件,并在从服务器  重新执行该事件,从而实现主从复制。2.主从服务器配置 ......
  • docker yum mysql
    Docker容器中使用Yum安装MySQL概述Docker是一个流行的容器化平台,它允许我们在独立、可移植的容器中运行应用程序。Yum(YellowdogUpdaterModified)是RedHatLinux和CentOS操作系统中的一个软件包管理器,它可以方便地用于安装、更新和删除软件包。本文将介绍如何在Docker容器中使用......
  • MySQL8 Bug 记录
    配置相关MySQL8安全插件更新导致的兼容性问题mysql8提供了新的功能,这些功能会影响用户创建或更新用户密码,以及使用那些仅支持mysql5登陆方式的客户端工具PasswordValidationOptionsandVariablesAuthenticationPlugins密码验证组件该组件要求用户必须设置符合一定......