当前位置: 首页 > news >正文

mysql的各种锁

全局锁

全局锁就是对整个数据库实例加锁,加上全局锁后,整个数据库将处于只读状态,后续的 DML 语句、DDL 语句,以及更新操作的事务提交语句都将被阻塞

全局锁的典型的使用场景是做全库的数据备份,需要对所有的表进行锁定,从而获取一致性视图,保证数据的一致性和完整性


表级锁

表级锁,每次操作都会锁住整张表,锁定粒度大,发生锁冲突的概率最高,并发度最低,应用在 MyISAM、InnoDB、BDB 等存储引擎中

对于表级锁,主要分为以下三类:

  • 表锁
  • 元数据锁(Meta Data Lock,MDL)
  • 意向锁

表锁

对于表锁,分为两类:

  • 表共享读锁(Read Lock,读锁)

  • 表独占写锁(Write Lock,写锁)

使用表锁的语法:

  • 加锁:lock table 表01 read 表02 write;
  • 释放锁:unlock tables;与 MySQL 服务器断开连接也会释放锁

读锁和写锁的区别

读锁不会阻塞其他客户端的读,但是会阻塞其它客户端的写

写锁既会阻塞其他客户端的读,也会阻塞其他客户端的写

元数据锁

元数据锁的加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上

元数据锁的主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作(为了避免 DML 语句和 DDL 语句之间的冲突,保证读写操作的正确性)

更简单的理解方式就是:在对表进行增删查改操作的时候,不能更改表的结构

那什么是元数据呢,大家可以简单地理解为表结构

意向锁

为了避免DML在执行时,加的行锁与表锁的冲突,在InnoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。

假设一张表中有一千万条数据,现在事务T1ID=8888888的这条数据加了一个行锁,此时来了一个事务T2,想要获取这张表的表级别写锁,写锁必须为排他锁,也就是在同一时刻内,只允许当前事务操作,如果表中存在其他事务已经获取了锁,目前事务就无法满足“独占性”,因此不能获取锁。

那思考一下,由于T1是对ID=8888888的数据加了行锁,那T2获取表锁时,是不是得先判断一下表中是否存在其他事务在操作?但因为InnoDB中有行锁的概念,所以表中任何一行数据上都有可能存在事务加锁操作,为了能精准的知道答案,MySQL就得将整张表的1000W条数据全部遍历一次,然后逐条查看是否有锁存在,那这个效率自然会非常的低。

有人可能会说,慢就慢点怎么了,能接受!但实际上不仅仅存在这个问题,还有另外一个致命问题,比如现在MySQL已经判断到了第567W行数据,发现前面的数据上都没有锁存在,正在继续往下遍历。

要记住MySQL是支持并发事务的,也就是MySQL正在扫描后面的每行数据是否存在锁时,万一又来了一个事务在扫描过的数据行上加了个锁怎么办?比如在第123W条数据上加了一个行锁。那难道又重新扫描一遍嘛?这就陷入了死循环,行锁和表锁之间出现了兼容问题。

由于行锁和表锁之间存在兼容性问题,提出了意向锁。意向锁实际上也是一种特殊的表锁,意向锁其实是一种“挂牌告知”的思想,好比日常生活中的出租车,一般都会有一个牌子,表示它目前是“空车”还是“载客”状态,而意向锁也是这个思想。

比如当事务T1打算对ID=8888888这条数据加一个行锁之前(行级别的读锁或写锁),就会先加一个表级别的意向锁。此时当事务T2尝试获取一个表级锁时,就会先看一下表上是否有意向锁,如果有的话再判断一下与自身是否冲突,比如表上存在一个意向共享锁,目前T2要获取的是表级别的读锁,那自然不冲突可以获取。但反之,如果T2要获取一个表级的写锁时,就会出现冲突,T2事务则会陷入阻塞,直至T1释放了锁(事务结束)为止。


行级锁

行级锁,每次操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低,并发度最高,应用在 InnoDB 存储引擎中

InnoDB 的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁,对于行级锁,主要分为三类

第一类:行锁(Record Lock),锁定单个行记录的锁,防止其他事务对此行进行 update 和 delete 操作,在 RC、RR 隔离级别下都支持

在这里插入图片描述

第二类:间隙锁(Gap Lock)锁定索引记录间隙(不含该记录),确保案引记录间隙不变,防止其他事务在这个间隙进行 insert 操作,产生幻读,在 RR 隔离级别下都支持

在这里插入图片描述

第三类:临键锁(Next-Key Lock)行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙 Gap,在 RR 隔离级别下支持

在这里插入图片描述

在进行增删查改语句的时候,所加的行锁类型情况如下

操作类型SQL 语句示例行锁类型说明
INSERT …排他锁自动加锁
DELETE …排他锁自动加锁
UPDATE …排他锁自动加锁
SELECT … FOR UPDATE排他锁需要手动在select后加FOR UPDATE
SELECT … LOCK IN SHARE MODE共享锁需要手动在select后加 LOCK IN SHARE MODE
SELECT … (正常)不加任何锁

默认情况下,InnoDB 引擎在 REPEATABLE READ 事务隔离级别运行,InnoDB 使用 Next-Key Locks 锁(临键锁)进行搜索和索引扫描,以防止幻读

行级锁的加锁规则

数据

主键IDNameAge
1lxx16
5lxx19
8lxx21
10lxx24
13lxx27

唯一索引等值查询

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

select * from demo where id=8 lock in share mode;
-- 查询 id=8的数据,加锁的基本单位是 next-key lock,因此事务A的加锁范围是 id (5, 8];  
-- 唯一索引(包括主键索引) 进行等值查询,且查询的记录存在,所以next-key lock 退化成记录锁,最终加锁的范围就是 id = 8 这一行。

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

select * from demo where id=6 lock in share mode;
-- 查询 id=6不存在的数据,加锁基本单位next-key lock,因此事务A的加锁范围是 id (5, 8];  
-- 唯一索引进行等值查询,由于查询的记录不存在,next-key lock 退化成间隙锁,因此最终加锁的范围是 (5,8)。  

唯一索引的范围查询

select * from demo where id>=5 and id<7 lock in share mode;
-- 首先最开始要找的记录是 id>=5,因此产生的临键锁 next-key lock 范围为:(1,5],但是由于 id 是唯一索引,且该记录是存在的,因此会退化成记录锁,也就是只会对 id = 5 这一行加锁;
-- 由于是范围查找,就会继续往后找存在的记录,也就是会找到 id = 8 这一行停下来,然后加 next-key lock (5, 8],但由于 id = 8 不满足 id < 7,所以会退化成间隙锁,加锁范围变为 (5, 8)。
-- 根据事务A加锁变化得出,目前有2把锁,行锁:id=5 , 间隙锁:(5,8)。

非唯一索引等值查询

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

select * from demo where age=21 lock in share mode; 
-- age共有2个锁,其锁范围 (19,21]、(21,24),也就是总范围是:(19,24)

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

select * from demo where age=17 lock in share mode; 
-- 非唯一索引等值查询记录不存在时,只会加next-key lock,并退化为Gap Lock间隙锁,即只会加一把锁。故查询age=17获得临键锁(16,19] ,并退化成间隙锁 (16,19)

非唯一索引的范围查询

select * from demo where age>=19 and age<22 lock in share mode;
-- 首先最开始要找的记录是 age>=19,因此产生的临键锁 next-key lock 范围为:(16,19]
-- 由于是范围查找,则继续往后找存在的记录,查询条件age<22 最终产生2个next-key lock,分别是 (19,21]、(21, 24]
-- 根据事务A产生的三把next-key lock,范围分别是:(16,19]、 (19,21]、(21, 24],总范围可以得出:(16,24]

文章转载自:

http://hkuBgP8O.Ltdxq.cn
http://5GPIbE8I.Ltdxq.cn
http://8i7l1u7W.Ltdxq.cn
http://oaCDU50d.Ltdxq.cn
http://atg0x4xL.Ltdxq.cn
http://hFTC9LiD.Ltdxq.cn
http://bwjVgmuu.Ltdxq.cn
http://hZ9fruPO.Ltdxq.cn
http://IvxRYtP4.Ltdxq.cn
http://FVsIbOdq.Ltdxq.cn
http://NMTMyIOy.Ltdxq.cn
http://YAMiyfP3.Ltdxq.cn
http://sS4Ex1R7.Ltdxq.cn
http://XGoePRRr.Ltdxq.cn
http://qQaCM3Qg.Ltdxq.cn
http://vTqci3ob.Ltdxq.cn
http://oBqx3SNd.Ltdxq.cn
http://k67EfxYx.Ltdxq.cn
http://qgPfMBEd.Ltdxq.cn
http://CDxAlea1.Ltdxq.cn
http://hmUSHo0j.Ltdxq.cn
http://YW7sEihL.Ltdxq.cn
http://en2fTShX.Ltdxq.cn
http://NMf4Q849.Ltdxq.cn
http://SGxhEKpF.Ltdxq.cn
http://qMFoqRlf.Ltdxq.cn
http://eczZTJlD.Ltdxq.cn
http://dOCjbEAA.Ltdxq.cn
http://90V7kPoh.Ltdxq.cn
http://Uws1uBNZ.Ltdxq.cn
http://www.dtcms.com/a/379468.html

相关文章:

  • Java大厂面试实录:AIGC与虚拟互动场景下的微服务与AI落地(附知识详解)
  • Kafka 学习笔记
  • 机械零件极限应力线图
  • 萤石安全生产监管解决方案:构建企业安全智能化防护网
  • sqlmap常用命令
  • MID认证:全球电力计量市场的通行证与中国协议兼容性分析
  • STM32开发(USART:IIC总线)
  • Spring框架中用到的设计模式
  • 从源码和设计模式深挖AQS(AbstractQueuedSynchronizer)
  • 四、计算机网络与分布式系统(中)
  • 半导体学习笔记
  • 深入解析Dart虚拟机运行原理
  • 一文教您解决Ubuntu ModuleNotFoundError: No module named ‘_tkinter‘问题
  • 部署合约常见的问题
  • Python快速入门专业版(二十三):for循环基础:遍历字符串、列表与range()函数(计数案例)
  • MySQL 非空约束(NOT NULL):看似简单,却决定数据质量的关键细节
  • 【笔记】悬架减振器的阻尼带宽
  • C++:迭代器失效问题(vector为例)
  • TDengine 选择函数 TAIL() 用户手册
  • 在Linux系统中清理大文件的方法
  • oracle里的int类型
  • 【开关电源篇】整流及其滤波电路的工作原理和设计指南-超简单解读
  • 第五章 Logstash深入指南
  • 猫狗识别算法在智能喂食器上的应用
  • 数据库事务详解
  • Linux学习:基于环形队列的生产者消费者模型
  • size()和length()的区别
  • Windows系统下安装Dify
  • 企业云环境未授权访问漏洞 - 安全加固笔记
  • sv时钟块中default input output以及@(cb)用法总结