mysql锁类型大全(简单了解 MySQL 中相关的锁)
mysql锁类型大全
简单了解 MySQL 中相关的锁
本文主要是带大家快速了解 InnoDB 中锁相关的知识
为什么需要加锁
首先,为什么要加锁?我想我不用多说了,想象接下来的场景你就能 GET 了。
你在商场的卫生间上厕所,此时你一定会做的操作是啥?锁门。如果不锁门,上厕所上着上着,啪一下门就被打开了,可能大概也许似乎貌似有那么一丁点的不太合适。
数据也是一样,在并发的场景下,如果不对数据加锁,会直接破坏数据的一致性,并且如果你的业务涉及到钱,那后果就更严重了。
锁门表情包
锁的分类
在 InnoDB 中,都有哪些锁?其实你应该已经知道了很多了,例如面试中会问你存储引擎 MyISAM 和 InnoDB 的区别,你会说 MyIASM 只有表锁,但是 InnoDB 同时支持行锁和表锁。你可能还会被问到乐观锁和悲观锁的区别是啥。
锁的概念、名词很多,如果你没有对锁构建出一个完整的世界观,那么你理解起来就会比较有阻碍,接下来我们把这些锁给分一下类。
按照锁的粒度
按照锁的粒度进行划分可以分为:
- 表锁
- 行锁
这里就不讨论页锁了,页锁是 BDB(BerkeleyDB) 存储引擎中才有的概念,我们这里主要讨论 InnoDB 存储引擎。
按照锁的思想
按照加锁的思想可以分为:
- 悲观锁
- 乐观锁
这里的悲观、乐观和你平时理解的名词是同一个意思。乐观锁认为大概率不会发生冲突,只在必要的时候加锁。而悲观锁认为大概率会冲突,所以无论是否必要加锁都会执行加锁操作。
按照兼容性
按照兼容性可以把锁划分为:
- 共享锁
- 排他锁
被加上共享锁的资源,能够和其他人进行共享,而如果被加上了排他锁,其他人在拿不到这把锁的情况下是无法进行任何操作的。
按照锁的实现
这里的实现就是 InnoDB 中具体的锁的种类了,分别有:
- 意向锁(Intention Locks)
- 记录锁(Record Locks)
- 间隙锁(Gap Locks)
- 临键锁(Next-Key Locks)
- 插入意向锁(Insert Intention Locks)
- 自增锁(AUTO-INC Locks)
即使按照这种分类来对锁进行了划分,看到了这么多的锁的名词可能仍然会有点懵。比如我SELECT ... FOR UPDATE 的时候到底加的是什么锁?
我们应该透过现象看本质,本质是什么?本质是锁到底加在了什么对象上,而这个很好回答:
- 加在了表上
- 加在了行上
而对于加在行上的锁,其本质又是什么?本质是将锁加在了索引上。
意向锁
在 InnoDB 中支持了不同粒度的锁,行锁和表锁。例如lock tables命令就会持有对应表的排他锁。为了使多种不同粒度的锁更实用,InnoDB 设计了意向锁。
意向锁是一种表级锁,它表明了接下来的事务中,会使用哪种类型的锁,它有以下两种类型:
- 共享意向锁(IS) 表明该事务会打算对表中的记录加共享锁
- 独占意向锁(IX) 则是加排他锁
例如,select ... for share就是加的共享意向锁,而SELECT .. FOR UPDATE则是加的独占意向锁。其规则如下:
- 一个事务如果想要获取某张表中某行的共享锁,它必须先获取该表的共享意向锁,或者独占意向锁。
- 同理,如果想获取排他锁,它必须先获取独占意向锁
下图是这几种锁的组合下相互互斥、兼容的情况
对照上面的表,在相互兼容的情况下,对应的事务就能获取锁,但是如果不兼容则无法获取锁,直到不兼容的锁释放之后才能获取。
看到这里你可能就会有问题了,那既然意向锁除了 LOCK TBALES 之外什么都不阻塞。那我要它何用?
还是通过例子,假设事务 A 获取了 student 表中 id = 100 这行的共享锁,之后事务 B 需要申请 student 表的排他锁。而这两把锁明显是冲突的,而且还是对于同一行。
那 InnoDB 需要如何感知 A 获取了这把锁?遍历整个 B+ 树吗?不,答案就是意向锁。事务 B 申请写表的排他锁时,InnoDB 会发现事务 A 已经获取了该表的意向共享锁,说明 student 表中已经有记录被共享锁锁住了。此时就会阻塞住。
并且,意向锁除了像LOCK TABLES这种操作之外,不会阻塞其他任何操作。换句话说,意向锁只会和表级别的锁之间发生冲突,而不会和行级锁发生冲突。因为意向锁的主要目的是为了表明有人即将、或者正在锁定某一行。
就像你去图书馆找书,你并不需要每个书架挨着挨着找,直接去服务台用电脑一搜,就知道图书馆有没有这本书。
记录锁
这就是记录锁,是行锁的一种。记录锁的锁定对象是对应那行数据所对应的索引。对索引不太清楚的可以看看这篇文章。
当我们执行SELECT * FROM student WHERE id = 1 FOR UPDATE语句时,就会对值为1的索引加上记录锁。至于要是一张表里没有索引该怎么办?这个问题在上面提到的文章中也解释过了,当一张表没有定义主键时,InnoDB 会创建一个隐藏的RowID,并以此 RowID 来创建聚簇索引。后续的记录锁也会加到这个隐藏的聚簇索引上。
当我们开启一个事务去更新 id = 1 这行数据时,如果我们不马上提交事务,然后再启一个事务去更新 id = 1 的行,此时使用 show engine innodb status查看,我们可以看到lock_mode X locks rec but not gap waiting的字样。
X是排他锁的意思,从这可以看出来,记录锁其实也可以分为共享锁、排他锁模式。当我们使用FOR UPDATE是排他,而使用LOCK IN SHARE MODE 则是共享。
而在上面字样中出现的 gap 就是另一种行锁的实现间隙锁。
间隙锁
对于间隙锁(Gap Locks)而言,其锁定的对象也是索引。为了更好的了解间隙锁,我们举个例子。
- SELECT name FROM student WHERE age BETWEEN 18 AND 25 FOR UPDATE
假设我们为 age 建立了非聚簇索引,运行该语句会阻止其他事务向 student 表中新增 18-25 的数据,无论表中是否真的有 age 为 18-25 的数据。因为间隙锁的本质是锁住了索引上的一个范围,而 InnoDB 中索引在底层的B+树上的存储是有序的。
再举个例子:
- SELECT * FROM student WHERE age = 10 FOR UPDATE;
值得注意的是,这里的 age 不是唯一索引,就是一个简单的非聚簇索引。此时会给 age = 10的数据加上记录锁,并且锁定 age < 10 的 Gap。如果当前这个事务不提交,其他事务如果要插入一条 age < 10 的数据时,会被阻塞住。
间隙锁是 MySQL 在对性能、并发综合考虑之下的一种折中的解决方案,并且只在**可重复读(RR)下可用,如果当前事务的隔离级别为读已提交(RC)**时,MySQL会将间隙锁禁用。
刚刚说了,记录锁分为共享、排他,间隙锁其实也一样。但是不同于记录锁的一点,共享间隙锁、排他间隙锁相互不互斥,这是怎么回事?
我们还是需要透过现象看到本质,间隙锁的目的是什么?
为了防止其他事务在 Gap 中插入数据
那共享、排他间隙锁在这个目标上是一致的,所以是可以同时存在的。
临键锁
临键锁(Next-Key Locks)是 InnoDB 最后一种行锁的实现,临键锁实际上是记录锁和间隙锁的组合。换句话说,临键锁会给对应的索引加上记录锁,并且外加锁定一个区间。
但是并不是所有临键锁都是这么玩的,对于下面的SQL:
- SELECT * FROM student WHERE id = 23;
在这种情况下,id是主键,唯一索引,无论其他事务插入了多少数据,id = 23这条数据永远也只有一条。此时再加一个间隙锁就完全没有必要了,反而会降低并发。所以,在使用的索引是唯一索引的时候,临键锁会降级为记录锁。
假设我们有10,20,30总共3条索引数据。那么对应临键锁来说,可能锁定的区间就会如下:
- (∞, 10]
- (10, 20]
- (20, 30]
- (30, ∞)
InnoDB 的默认事务隔离级别为可重复读(RR),在这个情况下,InnoDB 就会使用临键锁,以防止幻读的出现。
简单解释一下幻读,就是在事务内,你执行了两次查询,第一次查询出来 5 条数据,但是第二次再查,居然查出了 7 条数据,这就是幻读。
可能你在之前的很多博客,或者面试八股文上,了解到过 InnoDB 的RR事务隔离级别可以防止幻读,RR防止幻读的关键就是临键锁。
举个例子,假设 student 表中就两行数据,id分别为90和110.
- SELECT * FROM student WHERE id > 100 FOR UPDATE;
当执行该 SQL 语句之后,InnoDB就会给区间 (90, 110] 和(110,∞) 加上间隙锁,同时给 id=110 的索引加上记录锁。这样以来,其他事务就无法向这个区间内新增数据,即使 100 根本不存在。
插入意向锁
接下来是插入意向锁(Insert Intention Locks),当我们执行 INSERT 语句之前会加的锁。本质上是间隙锁的一种。
还是举个例子,假设我们现在有索引记录10、20,事务A、B分别插入索引值为14、16的数据,此时事务A和B都会用插入意向锁锁住 10-20 之间的 Gap,获取了插入意向锁之后就会获取14、16的排他锁。
此时事务A和B是不会相互阻塞的,因为他们插入的是不同的行。
自增锁
最后是自增锁(AUTO-INC Locks),自增锁的本质是表锁,较为特殊。当事务 A 向包含了 AUTO_INCREMENT 列的表中新增数据时,就会持有自增锁。而此时其他的事务 B 则必须要等待,以保证事务 A 取得连续的自增值,中间不会有断层。
原文链接:https://mp.weixin.qq.com/s/rB0MHssNG_9ivZP2ka-EYw
- mysql的日志怎么清除(MySQL删除了记录不生效的原因排查)
- mysqldump备份缺点(MySQL5.7 mysqldump备份与恢复的实现)
- mysql慢日志查询会输出插入语句吗(MySQL三种日志有啥用?如何提高MySQL并发度?)
- mysql基本查询方法(MySQL 重写查询语句的三种策略)
- mysql索引的弊端(MySQL 全文索引的原理与缺陷)
- mysql行级锁使用教程(浅析MySQL的lru链表)
- navicat连接mysql报错(解决Navicat Premium 连接 MySQL 8.0 报错"1251"的问题分析)
- idea向数据库中插入中文报错(Idea连接MySQL数据库出现中文乱码的问题)
- mysql编码设置
- mysql 查询语句group by用法(MySQL group by和order by如何一起使用)
- mysql快速创建索引(MySQL创建高性能索引的全步骤)
- docker进入mysql查看路径(Docker 环境运行 Mysql 和开启 Binlog 配置主从同步的设置方法)
- docker 镜像mysql(解决docker拉取mysql镜像太慢的情况)
- mpp数据库的客户端工具(xampp默认mysql数据库root密码的修改)
- mysql数值类型图解(详解mysql持久化统计信息)
- mysql和navicat怎么用(如何用Navicat操作MySQL)
- 今天会下雨吗(今天会下雨吗小说)
- 追连续剧,品古今联4 明代三杨,联妙诗佳(追连续剧品古今联4)
- 三杨 共辅四朝帝王,构建明帝国内阁行政圈(三杨共辅四朝帝王)
- 红色文化进国企(红色文化进国企)
- 车友的选择| 轮毂该如何选(车友的选择轮毂该如何选)
- 秦海璐炫耀和王新军热恋蜜事,不料对方吐槽她吃饱后肚子撅老高(秦海璐炫耀和王新军热恋蜜事)
热门推荐
- pandas数据分组后的处理(详解pandas如何去掉、过滤数据集中的某些值或者某些行?)
- 云服务器定时重启(云服务器无法正常关机/重启的几种原因)
- laravel后台框架(laravel-admin的多级联动方法)
- 云服务器有什么工作用(云服务器有什么用?怎么选择?)
- php数组详解(php数组和链表的区别总结)
- win7安装iis系统教程(win7环境下安装配置IIS服务器图文教程)
- docker容器默认内存大小(Docker 修改docker存储位置 修改容器镜像大小限制操作)
- 如何使用HttpModule实现sql防注入
- Ext.each的用法
- servu权限设置(Serv-U防溢出提权攻击解决设置方法)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9