【面试题】细说mysql中的各种锁

前言

作为一名IT从业人员,无论你是开发,测试还是运维,在面试的过程中,我们经常会被数据库,数据库中最经常被问到就是MySql。当面试官问MySql的时候经常会问道一个问题,”MySQL中有哪些锁?“当我们去网上找相应的资料的时候却是五花八门,张三说的一个样,李四说的另一个样。
like this…

案例一:

案例二:

案例三:

案例四:

搞得我们都不知道他们说到底对不对,全不全,…于是我们非常之困惑,面试的时候不知如何作答,正是为了解决这个问题,我查阅了很多书籍,国内外资料,写下这篇文章,希望对你有所帮助。

锁到底是个什么东西

维基百科是这样解释的:锁是一种保安设施,是人类为了保护自己的财产而发明的一种用钥匙才能开启的装置。就现代而言,是一种以钥匙、密码、电路或者其他用具来开启的封缄装置,用以防止物品被打开、移走兼具防护、管理甚至是装饰的作用。所以锁最重要的作用自然就是保护安全。


在计算机的世界里其实也一样,使用锁的目的几乎都是为了保证数据的安全可靠。在生活中锁千奇百怪,但我们可以将锁大致分为两种,一种是需要钥匙的,一种是不需要钥匙的,当然现代家庭中的指纹锁,数字密码锁都是需要钥匙的哈,只是钥匙不是实体钥匙而已。有很多朋友可能很纳闷,锁还有不需要钥匙的?答案是:有的
比如:

如果你来自农村,并且家里还有老宅那你可能也见过这样的锁:

这些锁都是不需要钥匙的,我们将之为”闩(shuan)锁“。
需要钥匙的锁就很常见了,比如:

再比如:

这种需要钥匙的锁我将之称为”锁“。

所以非常直观的感受就是虽然都为锁,但是闩锁比较”轻量“,自然也就没那么安全,而”锁“则麻烦一些,需要随身带着钥匙,所以相对也会更安全一些。相信到这里你已经对锁有比较好的理解了,那我们接着说数据库中的锁。

Mysql中的锁

在数据库中自然也将锁分成了两类,一类叫latch也就是闩锁,另一种叫lock(锁)。

latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差。在InnoDB存储引擎中,latch又可以分为mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
在数据库中,连接是一种珍贵的资源,连接自然不可能无限变多,也不可能同时被多个线程同时持有,这时候就需要用锁来保证同一时刻同一个连接只能被一个线程持有,这时候用到的锁就是我们说的闩锁。

lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。此外,lock,正如在大多数数据库中一样,是有死锁机制的。所以我们在看一些文章的时候经常会看到将MySQL的锁分为行锁、表锁、页锁,他们得出的依据就是来来自于此。(关于行锁、表锁、页锁我们先按下不表,后面展开说!)

这里借用MySQL技术内幕中一张图,对比一下latch与lock的区别:

总结一下:其实他俩最大的区别就是作用的范围不同,latch更像是我们日常开发过程中使用到的应用程序级别的“普通锁”。而lock则是为了操作数据库中数据的一种特殊的“事务锁”,平时我们面试的时候面试官问的也主要是这种为了操作数据库中数据而存在的事务锁。

在这里先提前给大家总结一下:

站在更高的维度看问题-锁无非就是读和写

不知你是否发现,无论是生活中的各种鸟锁,无非就是要不要用到钥匙,
然后把他分成闩锁和锁
。到了计算机界,锁无非也总的来说也就是两种,
一种是我拿到了锁我(一个事务)只让你(另一个事务)读只让你读,不让你写,另一种是:哥们我拿到锁了你们都往后靠一靠吧(连读都不让你读的),等我操作完了你们再来吧,好比厕所蹲坑,不可一个坑两个人同时蹲。所以你要明白“有空一起拉屎”只是调侃,可千万不能当真!

回归正题,于是乎按照严格我拿到锁了,你到底能不能读这个权限,将锁分为了两种:

  • 共享锁(S Lock):也叫做读锁
  • 排他锁(X Lock),也叫做写锁

注:你必须明白一点写的权限高于读,所以如果我说基于读这个权限,意思就是读都读不了,还写个毛啊!

所以我们总结再总结一下可以得出:

等等…我听说的全局锁、表锁、行锁你丫的没给我讲呢


前面我们已经讲了,锁无非就是读和写,这是从功能上来说,但是每个事务都有自己的表现形式呀,你说对吧?

在MySQL中,数据库中的数据被分为了"库–>表—>行",所以MySQL中的锁,按照锁的粒度分自然而然就产生对应的全局锁、表锁和行锁了哟!

  • 全局锁:锁定数据库中的所有表
  • 表级锁:每次操作锁住整张表
  • 行级锁:每次操作锁住对应的行数据

好了有了上面的铺垫,我们继续讲解这三种锁的使用,以便你在工作和面试中“惊艳四座、大杀四方、godlike!”

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

“后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。” 这几句话列位能理解的吧?

好吧,你们都能理解,那我也当个小丑🤡讲一下吧:

DML的写语句:sql语句中的update和delete语句都是写语句

DDL语句:就是要修改表结构的语句,比如ALTER TABLE table_name ADD column_name data_type
已经更新操作的事务提交语句:这一句优点难理解,直接上代码:

BEGIN -- 第一句UPDATE `subject` SET `name`='ccc12' WHERE id =1 -- 第二句COMMIT;--第三句

他想表达的意思就是,在锁库之前已经执行了前面两句sql然后库被锁住了,这时候如果再执行第三句,那么这个操作就会被阻塞!!

证明:
首先我们先执行第一句:


再执行第二句:


好的,我们去另一个事务中把库锁了:

这时候我们再去第一个事务中执行提交语句:

哎呀,家人们呐,看到了没,他被阻塞住了,不执行了!

我们再把锁释放了:

我们再回到第一个事务:

COMMIT已经执行成功了,从花费时间上也不难看出确实是被阻塞了呢!

全局锁这么猛(锁的粒度太™的大了),他在什么地方使用呢?

全局锁典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。但是在数据库中加全局并不是一个好选择,因为数据库中加全局锁,是一个比较重的操作,存在以下问题:

  • 1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。

  • 2.如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。

在lnnoDB引擎中,我们可以在备份时加上参数–single-transaction参数来完成不加锁的一致性数据备份。

mysqldump --single-transaction -uroot -p123456 test>test.sql

说完全局锁,我们接着说表锁,对,你没看错,是表锁,不是表嫂!

但是在这里我们要把它称为表级锁,而不是表锁,为什么要这么称呼呢?那肯定有是有道理滴,因为
同为表级锁,主要分为以下三类:

  • 1.表锁
  • 2.元数据锁(meta datalock,MDL)
  • 3.意向锁

他们都可以称为表(级)锁,对于表级锁来说,每次操作锁住整张表,在MyISAM、InnoDB、BDB等存储引擎中都有实现。由于每次操作锁住整张表,所以表锁的锁定粒度大,发生锁冲突的概率最高,并发度低。

表锁内心独白

这下真的要开始讲表锁了!!

看官老爷的心态--猴急

表锁主要分为两类:

  • 1.表共享读锁(read lock)
  • 2.表独占写锁(write lock)

共享读锁:当一张表被上了共享读锁以后,这张表只能被读不能被写,且读的话大家(不同的事务)都可以读,写的话大家都不能写。
举个例子好理解一点:

我们先将表上锁🔒:

BEGIN 
LOCK TABLES `subject` READSELECT * FROM `subject`  WHERE id=1COMMIT;

同一个事务内的读,如图:
第一步:

第二步:

不同的事务内的读:

同一事务内的写:

不同事务内的写:

独占写锁:当一张表被上了共享读锁以后,当前事务既能读数据也能写数据,同时还能修改表结构,别的事务既不能读数据也不能写数据,必须等到该锁被释放以后才能读写数据。(验证方式和上面一样,不再给图了)

这里一定要注意:我锁强调的是”别的事务“,而不是有些文章或者教学视频说的别的客户端!这是完全不同的概念,同一个客端可以上开启多个不同的事务!

总结如图:
图片来自黑马--管他黑马白马能骑的都是好马

表锁终于说完了,有些人看到这这里内容太多,估计已经暴躁了,想骂人!!

我也不想,可是它必须要讲!!

我们接着讲另一个表级锁–元数据锁

元数据锁(metadata lock) 也叫MDL,他的加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。在MySQL5.5中引I入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)。

说白了,元数据锁其实就是”表结构锁“没人这么叫,你可以这么理解,意思就是数据增删改查的时候能动了表结构,不然就会产生冲突,比如你在插入数据的时候,你把我表结构的其中一列给删了,你这让我这么插?

好的,我们继续讲解最后一个表级锁–意向锁

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

考虑这个例子:事务A锁住了表中的一行,让这一行只能读,不能写。之后,事务B申请整个表的写锁。如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的。数据库需要避免这种冲突,就是说要让B的申请被阻塞,直到A释放了行锁。

数据库要怎么判断这个冲突呢?

step1:判断表是否已被其他事务用表锁锁表

step2:判断表中的每一行是否已被行锁锁住。

注意: step2这样的判断方法效率实在不高,因为需要遍历整个表。于是就有了意向锁。在意向锁存在的情况下,事务A必须先申请表的意向共享锁,成功后再申请一行的行锁。
在意向锁存在的情况下,上面的判断可以改成step1:不变,step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。

意向锁分为两类:

  • 1.意向共享锁(IS):由语句select…lock in sharemode添加。与表锁共享锁(read)兼容,与表锁排它锁(write)互斥。

  • 2.意向排他锁(Ix):由insert、update、delete、select…forupdate添加。与表锁共享锁(read)及排它锁(write)都互斥,意向锁之间不会互斥。

可以通过以下SQL,查看意向锁及行锁的加锁情况:select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;

终于到了”行级锁“——千呼万唤始出来

我们继续学习行级锁,行级锁每次操作锁住对应行的数据,锁定粒度最小,发生锁冲突的概率最低,并发度最高。 InnoDB存储引擎支持行级锁,InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。(这一点非常重要)

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

  • **1.行锁(RecordLock):**锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC(读已提交)、RR(可重复读)隔离级别下都支持。

  • **2.间隙锁(GapLock):**锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。

  • **3.临键锁(Next-KeyLock):**行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。

行锁也被叫做记录锁,InnoDB实现了以下两种类型的行锁:

1.共享锁(S): 允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。

2.排他锁(X): 允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

其中insert、update、delete语句MySQL会自动为这些语句自动加上排他锁,select…lock in share mode语句会加上共享锁,select…for update加上排他锁,普通的select语句并不会加任何锁!

锁的升级与降级

默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。

第一类情况:

  • 针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。
  • InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁。

第二类情况:

  • 索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
  • 索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。
  • 索引上的范围查询(唯一索引),会访问到不满足条件的第一个值为止。

注意: 间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。

所以最后总结一下就是这样的:

最后

如果你能看到这里,那说明你真是太棒了,全文快五千字了,基本上把mysql的锁讲透了,同时你还有什么问题可以给我留言,一起进步!能一键三连的话,我将不甚感激!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/810930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-----Lambda表达式

文章目录 1 背景1.1 Lambda表达式的语法1.2 函数式接口 2 Lambda表达式的基本使用2.1 语法精简 3 变量捕获3.1 匿名内部类3.2 匿名内部类的变量捕获3.3 Lambda的变量捕获 4 Lambda在集合当中的使用4.1 Collection接口4.2 List接口4.3 Map接口 HashMap 的 forEach() 5 总结 1 背…

第十三届蓝桥杯真题:x进制减法,数组切分,gcd,青蛙过河

目录 x进制减法 数组切分 gcd 青蛙过河 x进制减法 其实就是一道观察规律的题。你发现如果a这个位置上的数x&#xff0c;b这个位置上的数是y&#xff0c;那么此位置至少是max(x,y)1进制。一定要把位置找对啊 #include <bits/stdc.h> using namespace std; typedef l…

如何卸载干净 IDEA(图文讲解)

更新时间 2022-12-20 11:一则或许对你有用的小广告 星球 内第一个项目&#xff1a;全栈前后端分离博客项目&#xff0c;演示地址&#xff1a;Weblog 前后端分离博客, 1.0 版本已经更新完毕&#xff0c;正在更新 2.0 版本。采用技术栈 Spring Boot Mybatis Plus Vue 3.x Vit…

如何开辟动态二维数组(C语言)

1. 开辟动态二维数组 C语言标准库中并没有可以直接开辟动态二维数组的函数&#xff0c;但我们可以通过动态一维数组来模拟动态二维数组。 二维数组其实可以看作是一个存着"DataType []"类型数据的一维数组&#xff0c;也就是存放着一维数组地址的一维数组。 所以&…

【C++成长记】C++入门 | 命名空间、输入输出、缺省参数

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;C​​​​​​​❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、C和C语言的区别和联系 二、命名空间 1、命名空间定义 2、命名空间使用 三、C输…

基于yolov9来训练人脸检测

YOLOv9是一个在目标检测领域内具有突破性进展的深度学习模型&#xff0c;尤其以其在实时性与准确性上的优秀表现而受到广泛关注。针对人脸检测这一特定任务&#xff0c;YOLOv9通过其架构创新和算法优化提供了强大的支持。 YOLOv9在继承了YOLO系列&#xff08;如YOLOv7、YOLOv8&…

二叉树--相同的树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true 思路 一、…

JavaEE 初阶篇-深入了解 CAS 机制与12种锁的特征(如乐观锁和悲观锁、轻量级锁与重量级锁、自旋锁与挂起等待锁、可重入锁与不可重入锁等等)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 乐观锁与悲观锁概述 1.1 悲观锁&#xff08;Pessimistic Locking&#xff09; 1.2 乐观锁&#xff08;Optimistic Locking&#xff09; 1.3 区别与适用场景 2.0 轻…

C++高级特性:柯里化过程与std::bind(六)

1、柯里化过程 1.1、operator()的引入 现在需要完成这样一个需求&#xff1a;有一个函数每次调用返回的结果不一样。例如&#xff1a;两次调用的返回值都不一样那么就可以达到这种目的 1.1.1、简单点的写法 可以给一个全局的变量&#xff08;静态变量&#xff09;&#xff…

深入理解JVM垃圾收集器

相关系列 深入理解JVM垃圾收集算法-CSDN博客 目前市面常见的垃圾收集器有Serial、ParNew、Parallel、CMS、Serial Old、Parallel Old、G1、ZGC以及有二种不常见的Epsilon、Shenandoah的&#xff0c;从上图可以看到有连线的的垃圾收集器是可以组合使用&#xff0c;是年轻代老年代…

Input DropDown 拼接成 select组件(基于antd和react)

前言&#xff1a;为什么不直接用select&#xff0c;还要舍近求远搞inputdropdown这种缝合怪&#xff0c;是因为antd的select不支持选中项再编辑&#xff0c;效果如图 比如&#xff1a;选中的lucy文案变成了placeholder不能再编辑了 封装此组件虽然比较简单&#xff0c;但还是有…

PLC互连全攻略:Profinet和EthernetIP实操演示

在今日的技术分享中&#xff0c;将详细探讨实现Profinet和Ethernet/IP的通信配置&#xff0c;以连接西门子PLC&#xff08;Profinet&#xff09;和罗克韦尔PLC&#xff08;Ethernet/IP&#xff09;。本篇将重点介绍专为通信而设计的Profinet转Ethernet/IP网关&#xff0c;在联接…

ActiveMQ介绍及linux下安装ActiveMQ

ActiveMQ介绍 概述 ActiveMQ是Apache软件基金下的一个开源软件&#xff0c;它遵循JMS1.1规范&#xff08;Java Message Service&#xff09;&#xff0c;是消息队列服务&#xff0c;是面向消息中间件&#xff08;MOM&#xff09;的最终实现&#xff0c;它为企业消息传递提供高…

【R语言从0到精通】-3-R统计分析(列联表、独立性检验、相关性检验、t检验)

上两次教程集中学习了R语言的基本知识&#xff0c;那么我们很多时候使用R语言是进行统计分析&#xff0c;因此对于生物信息学和统计科学来说&#xff0c;R语言提供了简单优雅的方式进行统计分析。教程参考《Rlearning》 3.1 描述性统计分析 3.1.1 载入数据集及summary函数 我…

【力扣题】关于单链表和数组习题

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

(Java)数据结构——图(第五节)Kruskal的实现最小生成树(MST)

前言 本博客是博主用于复习数据结构以及算法的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 Kruskal算法&#xff08;Kruskal的实现原理&#xff09; Kruskal算法的原理&#xff1a; 就是每次取最小的边&#xff0c;看看是不是与已经选择的构成回路&#x…

金融机构面临的主要AI威胁:身份伪造统与社会工程攻击

目录 攻击者利用AI威胁的过程 金融机构如何防范AI攻击 针对AI欺诈的解决方案 2023年11月&#xff0c;诈骗分子伪装成某科技公司郭先生的好友&#xff0c;骗取430万元&#xff1b;2023年12月&#xff0c;一名留学生父母收到孩子“被绑架”的勒索视频&#xff0c;被索要500万元赎…

ISTQB选择国内版,还是国际版呢

1, ISTQB简介 ISTQB&#xff08;International Software Testing Qualifications Board&#xff09;是一个国际软件测试资格认证机构&#xff0c;旨在提供一个统一的软件测试认证标准。ISTQB成立于2002年&#xff0c;是非盈利性的组织&#xff0c;由世界各地的国家或地区软件测…

Qt5 编译oracle数据库

库文件 1、Qt源码目录&#xff1a;D:\Qt5\5.15.2\Src\qtbase\src\plugins\sqldrivers\oci 2、oracle客户端SDK: https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html 下载各版本中的如下压缩包&#xff0c;一定要版本相同的 将两个压缩包…

事务,MySQL函数和索引详解

文章目录 事务简介提交方式手动提交事务 事务执行流程修改事务的默认提交方式 事务原理四大特性隔离级别 MySQL函数常见的日期函数判断函数case when字符串函数数字函数 MySQL性能(了解)索引概念分类MySQL索引语法数据结构(了解)BTreeBTree好处 优缺点优势劣势 创建原则 事务简…