【强烈建议收藏:MySQL面试必问系列之并发事务锁专题】

news2024/9/27 12:15:06

在这里插入图片描述

一.知识回顾

上节课我们一起学习了MySQL面试必问系列之事务,没有学习的同学可以看一下上一篇文章,肯定对你会有帮助,学习过的同学肯定知道,上节课我们留了一个小尾巴,这个小尾巴是什么呢?就是没有详细展开学习的MySQL事务并发锁的专题相关内容。那么这篇文章我们就一起来学习关于这方面的的内容,把我们整个知识框架搭建起来,话不多说,盘它。

二.什么是锁?锁的基本概念你知道吗?

2.1 锁的背景

再讲锁基本概念之前,我们先看这样一个例子,目的就是为了更好的理解锁的基本概念。
电商想必大家都知道,那么双十一肯定也是非常清楚的,活动当天的人流量是千万、亿级别的,但是商家的库存是有限的,不可能保证我们所有需要的用户都能抢到。所以,系统为了保证商家的商品库存不发生超卖现象,会对商品的库存进行锁控制。每次进行秒杀的时候都会锁住我们的库存,进行减库存的操作,当有用户正在下单某款商品最后一件时,系统会立马对该件商品进行锁定,防止其他用户也重复下单,直到支付动作完成才会释放,如果支付成功则立即减库存售罄,但是如果用户放弃支付,那么支付失败,我们会放出该库存,留给其他用户进行抢购。

上述过程是所有电商以及一些高并发场景以及系统开发过程中必须解决的一个问题,解决这个问题的关键就在于

2.2 锁的基本概念

在大致了解了锁的由来之后,接下来我们来了解一写关于锁的基本概念。

  1. 锁是计算机用以协调多个进程间并发访问同一共享资源的一种机制。MySQL中为了保证数据访问的一致性与有效性等功能,实现了锁机制,MySQL中的锁是在服务器层或者存储引擎层实现的。
  2. 在数据库中,除传统计算资源(CPU、RAM、I\O等)的争抢,数据也是一种供多用户共享的资源。如何保证数据并发访问的一致性,有效性,是所有数据库必须要解决的问题。锁冲突也是影响数据库并发访问性能的一个重要因素,因此锁对数据库尤其重要。
  3. 加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否已解除、释放锁等 ,都会增加系统的开销。

三.MySQL中锁的类型

3.1 行锁

3.1.1 行锁的基本概念

行锁MySQL的官方文档给出的定义

英文版

  • A record lock is a lock on an index record. Record locks always lock index records, even if a table is defined with no indexes. For such cases, InnoDB creates a hidden clustered index and uses this index for record locking.

中文版

  • 记录锁是索引记录上的锁。记录锁始终锁定索引记录,即使表的定义没有索引也是如此。对于这种情况,InnoDB 会创建一个隐藏的聚集索引,并使用此索引进行记录锁定。

从官方文档我们可以看出,行锁是作用在索引上的,即使我们在建表的时候没有定义一个索引,InnoDB也会创建一个聚簇索引并将其作为锁作用的索引。这个地方就必须在补充一下关于聚簇索引相关的知识。

拓展:
聚簇索引:
1.每一个InnoDB表都需要一个聚簇索引,有且只有一个。
2.如果我们在定义表的时候定义了主键,那么MySQL将使用主键作为聚簇索引;如果没有定义主键,那么MySQL将会把第一个唯一索引(而且要求NOT NULL)作为聚簇索引;如果上诉两种情况都没有满足,那么MySQL将自动创建一个名字为GEN_CLUST_INDEX的隐藏聚簇索引。

因为是聚簇索引,所以B+树上的叶子节点都存储了数据行,那么如果现在是二级索引呢?InnoDB中的二级索引的叶节点存储的是主键值(或者说聚簇索引的值),所以通过二级索引查询数据时,还需要将对应的主键去聚簇索引中再次进行查询。

3.1.2 行锁的种类

  1. 读锁(read lock),也叫共享锁(shared lock):加了锁的记录,所有事务都能去读取但不能修改,同时阻止其他事务获得相同数据集的排他锁;

  2. 写锁(write lock),也叫排他锁(exclusive lock):允许已经获得排他锁的事务去更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁;

  3. 意向锁(InnoDB表锁)

    知识补充:
    问题1:什么是意向锁呢?
    意向锁也是表级锁,分为读意向锁(IS锁)和写意向锁(IX锁)。当事务要在记录上加上行锁时,要首先在表上加上意向锁。这样判断表中是否有记录正在加锁就很简单了,只要看下表上是否有意向锁就行了,从而就能提高效率。
    问题2:为什么要引入意向锁呢?
    由于表锁和行锁虽然锁定范围不同,但是会相互冲突。当你要加表锁时,势必要先遍历该表的所有记录,判断是否有排他锁。这种遍历检查的方式显然是一种低效的方式,MySQL引入了意向锁,来检测表锁和行锁的冲突。
    问题3:意向锁的分类
    意向共享锁(IS):一个事务给一个数据行加共享锁时,必须先获得表的IS锁;
    意向排它锁(IX):一个事务给一个数据行加排他锁时,必须先获得该表的IX锁。
    问题4:意向锁之间存在并发安全的问题吗?
    意向锁之间是不会产生冲突的,它只会阻塞表级读锁或写锁。意向锁不于行级锁发生冲突。

3.1.3 行锁如何上锁

  1. 意向锁是 InnoDB 自动加的,不需要用户干预;
  2. 对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及的数据集加上排他锁;
  3. 对于普通的SELECT语句,InnoDB不会加任何锁;
  4. 事务可以通过以下语句显示给记录集添加共享锁或排他锁:

共享锁(S):此时其他 session 仍然可以查询记录,并也可以对该记录加 share mode 的共享锁。但是如果当前事务需要对该记录进行更新操作,则很有可能造成死锁。

select * from table_name where ... lock in share mode

# 1. 相关说明:in share mode 子句的作用就是将查找的数据加上一个share锁,这个就是表示其他的事务只能对这些数据进行简单的 select 操作,而不能进行 DML 操作。
# 2. 使用场景:为了确保自己查询的数据不会被其他事务正在修改,也就是确保自己查询到的数据是最新的数据,并且不允许其他事务来修改数据。与select for update不同的是,本事务在查找完之后不一定能去更新数据,因为有可能其他事务也对同数据集使用了 in share mode 的方式加上了S锁;
# 3. 性能分析:select lock in share mode 语句是一个给查找的数据上一个共享锁(S 锁)的功能,它允许其他的事务也对该数据上S锁,但是不能够允许对该数据进行修改。如果不及时的commit 或者rollback 也可能会造成大量的事务等待。

排他锁(X):其他session可以查询记录,但是不能对该记录加共享锁或排他锁,只能等待锁释放后在加锁。

select * from table_name where ... for update

# 1. 相关说明:在执行这个 select 查询语句的时候,会将对应的索引访问条目加上排他锁(X锁),也就是说这个语句对应的锁就相当于update带来的效果;
# 2. 使用场景:为了让确保自己查找到的数据一定是最新数据,并且查找到后的数据值允许自己来修改,此时就需要用到select for update语句;
# 3. 性能分析:select for update语句相当于一个update语句。在业务繁忙的情况下,如果事务没有及时地commit或者rollback可能会造成事务长时间的等待,从而影响数据库的并发使用效率。

行锁如何上锁,看图更直观,如下图所示:
在这里插入图片描述

3.1.4 锁模式的兼容矩阵

下面表显示了了各种锁之间的兼容情况:
注意:

  1. 下面的X与S是说表级的X锁和S锁,意向锁不和行级锁发生冲突;
  2. 如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;
  3. 如果两者不兼容,那么该事务就需要等待锁的释放。
XIXSIS
X
IX兼容兼容
S兼容兼容
IS兼容兼容兼容

3.1.5 行锁的类型

3.1.5.1 记录锁(Record Lock)
  1. 记录锁最简单的一种行锁形式。
  2. 行锁是加在索引上的,如果当你的查询语句不走索引的话,那么它就会升级到表锁,最终造成效率低下,所以在写SQL语句时需要特别注意。
3.1.5.2 间隙锁(Gap Lock)
  1. 当我们使用范围条件而不是相等条件去检索,并请求锁时,InnoDB就会给符合条件的记录的索引项加上锁;
  2. 键值在条件范围内但并不存在的记录,就叫做间隙,InnoDB在此时也会对间隙加锁
  3. 间隙锁是可以共存的,共享间隙锁与独占间隙锁之间是没有区别的,两者之间并不冲突。其存在的目的都是防止其他事务往间隙中插入新的纪录,故而一个事务所采取的间隙锁是不会去阻止另外一个事务在同一个间隙中加锁的。
  4. 当然也不是在什么时候都会去加间隙锁的。在 RU 和 RC 两种隔离级别下,即使你使用 select in share mode 或 select for update,也无法防止幻读(读后写的场景)。因为这两种隔离级别下只会有行锁,而不会有间隙锁。而如果是 RR 隔离级别的话,就会在间隙上加上间隙锁。
3.1.5.3 临键锁(Next-key Lock)
  1. 临键锁是记录锁与与间隙锁的结合,所以临键锁与间隙锁是一个同时存在的概念,并且临键锁是个左开有闭的区间。
  2. MySQL 默认隔离级别是RR,在这种级别下,如果你使用 select in share mode 或者 select for update 语句,那么InnoDB会使用临键锁(记录锁 + 间隙锁),因而可以防止幻读;
3.1.5.4 插入意向锁(Insert Intention Lock)
  1. 插入意向锁不影响其他事务加其他任何锁。也就是说,一个事务已经获取了插入意向锁,对其他事务是没有任何影响的;
  2. 插入意向锁与间隙锁和 Next-key 锁冲突。也就是说,一个事务想要获取插入意向锁,如果有其他事务已经加了间隙锁或 Next-key 锁,则会阻塞。
  3. 插入意图锁是一种间隙锁,在行执行 INSERT 之前的插入操作设置。如果多个事务 INSERT 到同一个索引间隙之间,但没有在同一位置上插入,则不会产生任何的冲突。假设有值为4和7的索引记录,现在有两事务分别尝试插入值为 5 和 6 的记录,在获得插入行的排他锁之前,都使用插入意向锁锁住 4 和 7 之间的间隙,但两者之间并不会相互阻塞,因为这两行并不冲突。
  4. 插入意向锁只会和 间隙或者 Next-key 锁冲突,正如上面所说,间隙锁作用就是防止其他事务插入记录造成幻读,正是由于在执行 INSERT 语句时需要加插入意向锁,而插入意向锁和间隙锁冲突,从而阻止了插入操作的执行。

3.1.6 不同类型锁之间的兼容

RECOREDGAPNEXT-KEYII GAP(插入意向锁)
RECORED兼容兼容
GAP兼容兼容兼容兼容
NEXT-KEY兼容兼容
II GAP兼容兼容

3.1.7 行锁默认存储引擎

行锁默认的存储引擎InnoDB,但是也支持表锁。

3.1.8 行锁加锁的特点

  1. 对数据库表中一行数据进行加锁
  2. 开销大
  3. 加锁效率慢
  4. 会出现死锁
  5. 锁粒度小,发生锁冲突概率最低,并发性高

3.1.8 行锁事务并发带来的问题

  1. 更新丢失
    解决:让事务变成串行操作,而不是并发的操作,即对每个事务开始—对读取记录加排他锁
  2. 脏读
    解决:发生在隔离级别为Read uncommitted,设置为其它隔离级别
  3. 不可重读
    解决:使用Next-Key Lock算法来避免
  4. 幻读
    解决:间隙锁(Gap Lock)

3.2 表锁

3.2.1 表锁的基本概念

表锁,顾名思义,就是直接给我们数据库的表加锁,在会话开始的地方使用 lock 命令将后续需要用到的表都加上锁,在表释放前,只能访问这些加锁的表,不能访问其他表,直到最后通过 unlock tables 释放所有表锁。

除了使用 unlock tables 显示释放锁之外,会话持有其他表锁时执行lock table 语句会释放会话之前持有的锁;会话持有其他表锁时执行 start transaction 或者 begin 开启事务时,也会释放之前持有的锁。

3.2.2 表锁种类

  1. 读锁(read lock),也叫共享锁(shared lock)针对同一份数据,多个读操作可以同时进行而不会互相影响(select)
  2. 写锁(write lock),也叫排他锁(exclusive lock)当前操作没完成之前,会阻塞其它读和写操作(update、insert、delete)

3.2.3 表锁如何上锁

表锁如何上锁,看图更直观,如下图所示:
在这里插入图片描述

3.2.4 表锁默认存储引擎

表锁默认的存储引擎MyISAM

3.2.5 表锁加锁的特点

  1. 对整张表加锁
  2. 开销小
  3. 加锁快
  4. 无死锁
  5. 锁粒度大,发生锁冲突概率大,并发性低

3.2.6 结论

  1. 读锁会阻塞写操作,不会阻塞读操作
  2. 写锁会阻塞读和写操作
  3. MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎,因为写锁以后,其它线程不能做任何操作,大量的更新使查询很难得到锁,从而造成永远阻塞。

四.什么是快照读和当前读?

4.1 快照读

快照读就是读取的是快照数据,读取的是历史数据,不加锁的简单Select 都属于快照读。

SELECT * FROM user WHERE ...

4.2 当前读

当前读就是读的是最新数据,而不是历史的数据。加锁的 SELECT,或者对数据进行增删改都会进行当前读。

SELECT * FROM user LOCK IN SHARE MODE;
SELECT FROM user FOR UPDATE;
INSERT INTO user values ...
DELETE FROM user WHERE ...
UPDATE user SET ...

五.MySQL如何解决幻读和不可重复度?

MySQL如何解决幻读和不可重复读?

深入学习MySQL事务:ACID特性的实现原理

六.行锁和表锁排查锁问题

参考图片的地址放到了最下面,感兴趣的同学可以看看该内容
在这里插入图片描述

七.死锁

参考图片的地址放到了最下面,感兴趣的同学可以看看该内容
在这里插入图片描述

总结

MySQL系列的文章也是面试官最喜欢问的一个点,所以大家一定要好好准备,是你拿下理想offer、理想薪资必备的点。

特别感谢

参考文章地址

一张图彻底搞懂 MySQL 的锁机制

【MySQL】MySQL中的锁机制

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

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

相关文章

MPI ubuntu安装,mpicc,mpicxx,mpif90的区别

介绍 MPI是并行计算的一个支持库,支持对C、C、fortran语言进行并行计算。 安装基础环境 ubuntu进行gcc/g/gfortran的安装: gcc: ubuntu下自带gcc编译器。可以通过gcc -v命令来查看是否安装。 g: sudo apt-get install buil…

【Python学习笔记】第二十四节 Python 正则表达式

一、正则表达式简介正则表达式(regular expression)是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特…

Day07-flex布局

文章目录弹性布局一 简介二 弹性容器案例-让多个div排成一行三 容器项目的对齐方式案例1-justify-content(主轴对齐)案例2-flex-wrap(换行)案例3-align-items(侧轴对齐)案例4-align-self(项目垂直对齐)案例5-flex-direction(改变轴向)案例6-弹性布局应用四 弹性项目-flex属性案…

离开央视的欧阳夏丹,在艺考培训机构当老师,是金子到哪都会发光

说起中央电视台,大家都认为这是主持界的殿堂,但凡能在这里工作的人,都是出类拔萃的人才。在中央电视台,确实也出现过很多人才,比如说主持界的康辉、撒贝宁、朱军、周涛等等。 除了以上这些主持人,欧阳夏丹也…

【高效办公】批量生成固定模板的文件夹名称

老师让你按照他的要求生成每位学生的文件夹,你是学委,让你马上完成该任务,但你又不想是手动一个一个码字,因此聪明的你就看到了本篇文章啦!!! 虽说一个人懒惰,并不是好的事情。 但这个似乎合情合理啊~ 然后,就动手想办法,一开始就真的打算码字了。。 思路 在实际开…

机器学习笔记之狄利克雷过程(二)基于标量参数作用的推导过程

机器学习笔记之狄利克雷过程——基于标量参数作用的推导过程引言回顾:狄利克雷过程——基本介绍狄利克雷过程——定义小插曲:狄利克雷分布的简单性质关于标量参数作用的推导过程引言 上一节以高斯混合模型为引,简单介绍了狄利克雷过程(Diric…

虹科分享| 浅谈HK-Edgility边缘计算平台

上周,我们推出了虹科新品HK-Edgility边缘计算平台以及uCPE解决方案。本篇文章我们再来谈一谈到底什么是边缘计算?为什么需要边缘计算?边缘计算和云计算有什么关系?HK-Edgility边缘计算平台将为您带来什么?一、边缘计算…

【C++】vector实现(深浅拷贝详细理解,迭代器失效)

🍅可以先去这个网站看一下个个函数的功能 本文不再详细介绍,vector的底层还是顺序表,我讲的很详细,建议没学过顺序表的先预习一下(主页搜索顺序表,还有配套习题) C网站关于vector的接口函数信息…

雅思积累(十八)同义替换

同义替换:sophisticated —— complicatedspecific —— detailed —— particularquantity —— wealth —— volume —— numbersettle —— schedule —— arrange —— fixswift —— rapid —— fast —— quickexpertise —— professional knowledge —— sk…

【云原生kubernetes】k8s中job与cronjob使用详解

一、前言 job,顾名思义就是任务,job的概念在很多框架中都有,而且实际业务场景中也使用非常广泛,比如大家熟悉的hadoop,客户端可以向集群提交一个job,然后集群根据一定的调度策略来处理这个job; …

【2023unity游戏制作-mango的冒险】-6.关卡设计

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 收录于专栏:unity游戏制作 ⭐mango的冒险关卡设计⭐ 文章目录⭐mango的冒险关卡设计⭐👨‍&#…

软件测试之jira

Jira 1. Jira 概述 JIRA 是澳大利亚 Atlassian 公司开发的一款优秀的问题跟踪管理软件工具,可以对各种类型的问题进行跟踪管理,包括缺陷、任务、需求、改进等。JIRA采用J2EE技术,能够跨平台部署。它正被广泛的开源软件组织,以及…

更新 TKK 失败,请检查网络连接。谷歌翻译 translation插件不能用解决办法 亲测有效

谷歌翻译无法使用,谷歌回应解释是,谷歌翻译使用率过低,所以选择停止服务。网上也有说法,指出根本原因为,提供API接口的googleapis被墙,这导致js文件和字体资源无法加载。 这里提供两种解决办法 方案一 修…

枯燥迷茫?先来玩玩这些经典的计算机视觉项目

B站|公众号:啥都会一点的研究生 颜色检测 从检测颜色到绿幕应用(用自定义视频或背景替换绿色背景),再到简单的照片编辑软件,构建颜色识别器是计算机视觉入门的一个很棒的项目 项目地址:https://github.…

PostgresSQL存储过程和触发器

在次之前首先要搞清楚一个概念 存储过程和触发器,是在基础sql语句之后的另一门语言,类似小学的加减乘除和奥数的关系,他们虽然都是数学,但是运算复杂度和定向思维都有了很大程度的不同 这篇文章不打算把存储过程和触发器事无巨细…

SAP 详细解析SCC4

事务代码:SCC4,选择一个客户端,点击进入,如图: 一、客户端角色 客户控制:客户的角色(生产性,测试,...) 此属性表示 R/3 系统中的客户端角色。其中可能包括…

简单分析Linux虚拟化KVM-Qemu之vhost-net

说明: KVM版本:5.9.1 QEMU版本:5.0.0 工具:Source Insight 3.5, Visio 1. 概述 让我们先来看看问题的引入,在之前的virtio系列文章中,网络虚拟化的框架如下图所示: ​ ​ Qemu中的…

WebRTC-NACK、Pacer和拥塞控制和FEC

NACK机制发送端实现NACK的三个重点流程:发送RTP报文,实时存储报文到packet_history_队列处理接收到的RTCP NACK报文把nack包里的序号放到nack_sequence_numbers丢包队列重发NACK反馈的RTP报文重发报文这里有三点需要注意:1)会判断…

Allegro如何查看PCB上器件的库路径操作指导

Allegro如何查看PCB上器件的库路径操作指导 在做PCB设计的时候,有时需要检查PCB上器件使用的库的路径是否正确,Allegro支持快速将PCB上所有器件的库路径都列出来 如下图 如何显示这个报表,具体操作如下 点击Tools点击Report

蓝桥杯-求和问题

蓝桥杯-求和问题1、问题描述2、解法一:暴力解法(两层循环)3、解法二:结合律(一层循环解决)1、问题描述 给定 n 个整数 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,...,an​,求它们两两相乘再相加的和,即: Sa1.a2a1.a3...a…