『 MySQL篇 』:MySQL 锁机制介绍_mysql锁-程序员宅基地

技术标签: MySQL剖析    mysql  数据库  

目录

一. 概述

二. 全局锁

三 . 表级锁

三. 行级锁


一. 概述

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

MySQL中的锁按照锁的粒度分,分为一下三类:

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

二. 全局锁

a. 介绍

全局锁就是对数据库的整个实例加锁, 加锁之后整个实例就处于只读状态,后续的DML写语句,DDL语句,以及更新操作的事务提交语句都会被阻塞,全局锁的典型使用场景就是进行全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

为什么进行全库备份时候加全局锁呢?

下面我们通过一个简单的例子来介绍一下不加全局锁时,可能出现的问题

假设数据库中存在着三张表 , tb_stock 库存表,tb_order 订单表,tb_orderlog 订单日志表。

73c0ce1e007e5d1245091386faf5ed9f.png

在进行数据备份时 :

  • 先备份了 tb _ stock 表
  • 然后接下来, 在业务系统中,执行了下单操作,扣减库存, 生成订单,(更新 tb_stock 表, 插入 tb _ order 表)
  • 然后再执行备份 tb_order 表 的逻辑
  • 业务中执行插入订单日志的操作
  • 最后 , 备份了 tb_orderlog 表

再上述的执行过程中, 备份出来的数据是存在问题的 , 因为备份出来的数据 , tb_stock 表 和 tb_order 表 存在着数据不一致的问题, 有最新的订单信息 , 但是总的库存数没有发生变化

那如何规避这种数据不一致的现象呢 , 此时就需要借助 MySQL 的全局锁来解决:

此时 , 我们再来分析一下加了全局锁之后的情况:

c0bab27bf0ed3f6e49f79cfd0eb92f25.png

在进行数据库的逻辑备份之前, 先对数据库加上全局锁,一旦加上全局锁之后,其他的DDL,DML全部都处于阻塞状态,

但是可以执行DQL语句,也就是只读状态,而数据备份就是查询操作, 那么在数据备份的过程中 , 数据库中的数据是不会发生变化的,这样就保证了数据的完整性和一致性.

b. 操作

  • 加全局锁
flush tables with read lock;
  • 数据备份
mysqldump -uroot –p1234 itcast > itcast.sql
  • 释放锁
unlock tables;

c. 特点

数据库中如果加全局锁 , 是一个粒度比较重的操作, 容易存在以下问题:

  • 如果在主库上进行备份,那么在备份期间都不能执行更新操作,业务基本就处于停摆
  • 如果在从库上进行备份,那么在备份期间,从库不能执行主库同步过来的二进制文件 ,就会导致主从延迟.

在 InnoDB 引擎中, 可以通过备份时增加一个参数来完成不加锁的数据一致性备份

mysqldump --single-transaction -uroot –p123456 itcast > itcast.sql

三 . 表级锁

表级锁 , 顾名思义,每次操作能够锁住整张表, 锁定粒度大,发生锁冲突概率较高,并发度最低 , 通常应用在 InnoDB , MyISAM, BDB 等引擎当中, 此处我们只对 InnoDB 中的表级锁进行详解:

1. 表锁

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

  1. 表锁
  2. 元数据锁
  3. 意向锁

对于表锁 , 主要分为两类

  1. 表共享读锁(read lock )

5b5e4f20da17276396b7674325f38e63.png

特点 : 对指定表加了读锁之后,当客户端一进行读操作时,不会影响客户端二的读,但是都会阻塞两哥客户端的写操作.

  1. 表独占写锁(write lock)

bb0e5be550349d7f6fda981b55380aeb.png

针对指定表增加了独占写锁之后, 客户端一可以针对表进行读和写, 而客户端二的读和写就会被阻塞

语法:

  • 加锁:lock tables 表名... read/write。
  • 释放锁:unlock tables / 客户端断开连接 。

总结: 读锁不会阻塞其他客户端的读 , 但是会阻塞写 , 写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写。

2. 元数据锁

元数据锁,简写MDL。MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性

这里的元数据,大家可以简单理解为就是一张表的表结构。 也就是说,某一张表涉及到未提交的事务时,是不能够修改这张表的表结构的。

在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)。

3c696d22fb2338097dbc9539001206e7.png

那如果数据库有一个长事务(所谓的长事务,就是开启了事务,但是一直还没提交),那在对表结构做变更操作的时候,可能会发生意想不到的事情,比如下面这个顺序的场景:

  1. 首先,线程 A 先启用了事务(但是一直不提交),然后执行一条 select 语句,此时就先对该表加上 MDL 读锁;
  2. 然后,线程 B 也执行了同样的 select 语句,此时并不会阻塞,因为「读读」并不冲突;
  3. 接着,线程 C 修改了表字段,此时由于线程 A 的事务并没有提交,也就是 MDL 读锁还在占用着,这时线程 C 就无法申请到 MDL 写锁,就会被阻塞,
  4. 那么在线程 C 阻塞后,后续有对该表的 select 语句,就都会被阻塞,如果此时有大量该表的 select 语句的请求到来,就会有大量的线程被阻塞住,这时数据库的线程很快就会爆满了。

这是因为申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁,一旦出现 MDL 写锁等待,会阻塞后续该表的所有 CRUD 操作。

共享锁:允许多个事务同时持有该锁,用于读取数据时,避免其他事务对数据进行修改。共享锁不会阻塞其他事务的共享锁请求,但会阻塞其他事务的独占锁和排他锁请求。

独占锁:只允许一个事务持有该锁,用于修改数据时,防止其他事务同时修改同一数据。独占锁会阻塞其他事务的共享锁和独占锁请求,但不会阻塞其他事务的排他锁请求。

排他锁:只允许一个事务持有该锁,用于修改数据时,防止其他事务同时修改同一数据。排他锁会阻塞所有其他事务的锁请求,包括共享锁、独占锁和排他锁。

MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的

  • 操作

查看元数据锁的加锁情况

mysql> select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks;
+-------------+--------------------+----------------+--------------+---------------+
| object_type | object_schema      | object_name    | lock_type    | lock_duration |
+-------------+--------------------+----------------+--------------+---------------+
| TABLE       | MySQL_Advanced     | tb_user        | SHARED_READ  | TRANSACTION   |
| TABLE       | MySQL_Advanced     | tb_user        | SHARED_READ  | TRANSACTION   |
| TABLE       | MySQL_Advanced     | tb_user        | SHARED_WRITE | TRANSACTION   |
| TABLE       | MySQL_Advanced     | user_logs      | SHARED_WRITE | TRANSACTION   |
| TABLE       | performance_schema | metadata_locks | SHARED_READ  | TRANSACTION   |
+-------------+--------------------+----------------+--------------+---------------+
5 rows in set (0.00 sec)

3. 意向锁

  1. 介绍

为了避免在DML进行执行时, 加的行锁与表锁相互冲突, 在 InnoDB 引擎中引入了意向锁, 使得表锁不需要去检查每行是否加锁 .

假如没有意向锁的情况下 , 客户端 一对表加了行锁之后, 客户端二如何给表进行加锁呢?

首先, 客户端一 , 开启一个事务, 然后执行 DML 操作, 在执行DML语句时, 会对涉及到的行进行加行锁.

当客户端二想要对这张表进行加表锁时,会检查当前表是否有对应的行锁,如果没有,则添加表锁,此时就会从第一行数据检查到最后一行 , 效率较低.

b5c65329dce8c7da4c4b56b0fe2a6d2a.png

有了意向锁之后, 在执行DML操作时,会对涉及的行加上行锁,同时也会给该表加上意向锁.

abaccfe82b113d205692b45f1c736a5b.png

而其他客户端对该表进行加表锁时,就可以根据是否存在意向锁来判断是否可以成功加锁.

  1. 分类
  • 意向共享锁 : 与表锁共享锁兼容, 与表锁排他锁互斥
  • 意向排他锁: 与表锁排他锁和表锁共享锁都互斥

意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables ... read)和独占表锁(lock tables ... write)发生冲突。

一旦事务提交了, 意向共享锁与意向排他锁都会释放

执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁 , 这样就可以快速判断表中是否有记录加锁.

三. 行级锁

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

InnoDB 引擎与 MySlAM 引擎的三大区别:事务 外键 行锁

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

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

InnoDB中实现了以下两种类型的行锁:

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁
  • 排他锁(X):允许排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。

两种行锁的兼容情况如下:

format,png

-- 会话 1
BEGIN;
SELECT * FROM orders WHERE id = 1 FOR UPDATE;
-- 对 id=1 的数据行进行修改
UPDATE orders SET amount = amount + 100 WHERE id = 1;
COMMIT;

-- 会话 2
BEGIN;
-- 因为会话 1 对 id=1 的数据行进行了行锁,所以会话 2 不能同时对该行进行修改,
-- 如果执行下面的语句会一直等待会话 1 的事务提交或回滚
UPDATE orders SET amount = amount - 50 WHERE id = 1;
  1. 间隙锁

间隙锁:指对一个索引范围中的“空隙”进行锁定,防止其他事务在这个范围内插入新数据。间隙锁用于解决幻读问题。

例如在某个事务中执行了一个范围查询,然后在范围内的间隙处插入了新数据,这时再次执行相同的查询,会发现有一些行出现了两次,这就是幻读。通过间隙锁,可以防止其他事务插入新的数据,从而避免幻读。

假设,表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。

format,png

-- 会话 1
BEGIN;
-- 对 id 大于 1 小于 10 的范围进行间隙锁定
SELECT * FROM orders WHERE id > 1 AND id < 10 FOR UPDATE;
-- 间隙锁会阻止其他事务在 id 大于 1 小于 10 的范围内插入数据,
-- 但允许其他事务在该范围之外的位置插入数据
COMMIT;

-- 会话 2
BEGIN;
-- 因为会话 1 对 id 大于 1 小于 10 的范围进行了间隙锁定,所以会话 2 不能在该范围内插入数据,
-- 如果执行下面的语句会一直等待会话 1 的事务提交或回滚
INSERT INTO orders (id, amount) VALUES (5, 500);
  1. 临键锁

临键锁与间隙锁的不同之处在于,他所锁定的不只是一个范围,还包括了锁定记录本身。

  • 索引上的等值查询(非唯一普通索引),向右遍历时最后一个值不满足查询需求时,临键锁退化为间隙锁。

假设,表中有一个范围 id 为(3,5] 的 next-key lock,那么其他事务即不能插入 id = 4 记录,也不能修改 id = 5 这条记录。

format,png

所以,临键锁即能保护该记录,又能阻止其他事务将新纪录插入到被保护记录前面的间隙中。

临键锁之间的X,S锁之间的互斥关系同样遵循行锁之间的互斥关系。

  • 总结:

在 InnoDB 中,默认情况下是使用行锁实现事务隔离级别的。当需要锁定一整张表时,可以使用表锁;当需要解决幻读问题时,可以使用间隙锁。在使用间隙锁时,需要注意锁的范围,避免影响其他事务的正常操作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_56361048/article/details/131073620

智能推荐

艾美捷Epigentek DNA样品的超声能量处理方案-程序员宅基地

文章浏览阅读15次。空化气泡的大小和相应的空化能量可以通过调整完全标度的振幅水平来操纵和数字控制。通过强调超声技术中的更高通量处理和防止样品污染,Epigentek EpiSonic超声仪可以轻松集成到现有的实验室工作流程中,并且特别适合与表观遗传学和下一代应用的兼容性。Epigentek的EpiSonic已成为一种有效的剪切设备,用于在染色质免疫沉淀技术中制备染色质样品,以及用于下一代测序平台的DNA文库制备。该装置的经济性及其多重样品的能力使其成为每个实验室拥有的经济高效的工具,而不仅仅是核心设施。

11、合宙Air模块Luat开发:通过http协议获取天气信息_合宙获取天气-程序员宅基地

文章浏览阅读4.2k次,点赞3次,收藏14次。目录点击这里查看所有博文  本系列博客,理论上适用于合宙的Air202、Air268、Air720x、Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持)。  先不管支不支持,如果你用的是合宙的模块,那都不妨一试,也许会有意外收获。  我使用的是Air720SL模块,如果在其他模块上不能用,那就是底层core固件暂时还没有支持,这里的代码是没有问题的。例程仅供参考!..._合宙获取天气

EasyMesh和802.11s对比-程序员宅基地

文章浏览阅读7.7k次,点赞2次,收藏41次。1 关于meshMesh的意思是网状物,以前读书的时候,在自动化领域有传感器自组网,zigbee、蓝牙等无线方式实现各个网络节点消息通信,通过各种算法,保证整个网络中所有节点信息能经过多跳最终传递到目的地,用于数据采集。十多年过去了,在无线路由器领域又把这个mesh概念翻炒了一下,各大品牌都推出了mesh路由器,大多数是3个为一组,实现在面积较大的住宅里,增强wifi覆盖范围,智能在多热点之间切换,提升上网体验。因为节点基本上在3个以内,所以mesh的算法不必太复杂,组网形式比较简单。各厂家都自定义了组_802.11s

线程的几种状态_线程状态-程序员宅基地

文章浏览阅读5.2k次,点赞8次,收藏21次。线程的几种状态_线程状态

stack的常见用法详解_stack函数用法-程序员宅基地

文章浏览阅读4.2w次,点赞124次,收藏688次。stack翻译为栈,是STL中实现的一个后进先出的容器。要使用 stack,应先添加头文件include<stack>,并在头文件下面加上“ using namespacestd;"1. stack的定义其定义的写法和其他STL容器相同, typename可以任意基本数据类型或容器:stack<typename> name;2. stack容器内元素的访问..._stack函数用法

2018.11.16javascript课上随笔(DOM)-程序员宅基地

文章浏览阅读71次。<li> <a href = "“#”>-</a></li><li>子节点:文本节点(回车),元素节点,文本节点。不同节点树:  节点(各种类型节点)childNodes:返回子节点的所有子节点的集合,包含任何类型、元素节点(元素类型节点):child。node.getAttribute(at...

随便推点

layui.extend的一点知识 第三方模块base 路径_layui extend-程序员宅基地

文章浏览阅读3.4k次。//config的设置是全局的layui.config({ base: '/res/js/' //假设这是你存放拓展模块的根目录}).extend({ //设定模块别名 mymod: 'mymod' //如果 mymod.js 是在根目录,也可以不用设定别名 ,mod1: 'admin/mod1' //相对于上述 base 目录的子目录}); //你也可以忽略 base 设定的根目录,直接在 extend 指定路径(主要:该功能为 layui 2.2.0 新增)layui.exten_layui extend

5G云计算:5G网络的分层思想_5g分层结构-程序员宅基地

文章浏览阅读3.2k次,点赞6次,收藏13次。分层思想分层思想分层思想-1分层思想-2分层思想-2OSI七层参考模型物理层和数据链路层物理层数据链路层网络层传输层会话层表示层应用层OSI七层模型的分层结构TCP/IP协议族的组成数据封装过程数据解封装过程PDU设备与层的对应关系各层通信分层思想分层思想-1在现实生活种,我们在喝牛奶时,未必了解他的生产过程,我们所接触的或许只是从超时购买牛奶。分层思想-2平时我们在网络时也未必知道数据的传输过程我们的所考虑的就是可以传就可以,不用管他时怎么传输的分层思想-2将复杂的流程分解为几个功能_5g分层结构

基于二值化图像转GCode的单向扫描实现-程序员宅基地

文章浏览阅读191次。在激光雕刻中,单向扫描(Unidirectional Scanning)是一种雕刻技术,其中激光头只在一个方向上移动,而不是来回移动。这种移动方式主要应用于通过激光逐行扫描图像表面的过程。具体而言,单向扫描的过程通常包括以下步骤:横向移动(X轴): 激光头沿X轴方向移动到图像的一侧。纵向移动(Y轴): 激光头沿Y轴方向开始逐行移动,刻蚀图像表面。这一过程是单向的,即在每一行上激光头只在一个方向上移动。返回横向移动: 一旦一行完成,激光头返回到图像的一侧,准备进行下一行的刻蚀。

算法随笔:强连通分量-程序员宅基地

文章浏览阅读577次。强连通:在有向图G中,如果两个点u和v是互相可达的,即从u出发可以到达v,从v出发也可以到达u,则成u和v是强连通的。强连通分量:如果一个有向图G不是强连通图,那么可以把它分成躲个子图,其中每个子图的内部是强连通的,而且这些子图已经扩展到最大,不能与子图外的任一点强连通,成这样的一个“极大连通”子图是G的一个强连通分量(SCC)。强连通分量的一些性质:(1)一个点必须有出度和入度,才会与其他点强连通。(2)把一个SCC从图中挖掉,不影响其他点的强连通性。_强连通分量

Django(2)|templates模板+静态资源目录static_django templates-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏18次。在做web开发,要给用户提供一个页面,页面包括静态页面+数据,两者结合起来就是完整的可视化的页面,django的模板系统支持这种功能,首先需要写一个静态页面,然后通过python的模板语法将数据渲染上去。1.创建一个templates目录2.配置。_django templates

linux下的GPU测试软件,Ubuntu等Linux系统显卡性能测试软件 Unigine 3D-程序员宅基地

文章浏览阅读1.7k次。Ubuntu等Linux系统显卡性能测试软件 Unigine 3DUbuntu Intel显卡驱动安装,请参考:ATI和NVIDIA显卡请在软件和更新中的附加驱动中安装。 这里推荐: 运行后,F9就可评分,已测试显卡有K2000 2GB 900+分,GT330m 1GB 340+ 分,GT620 1GB 340+ 分,四代i5核显340+ 分,还有写博客的小盒子100+ 分。relaybot@re...

推荐文章

热门文章

相关标签