MySQL的全局锁和表级锁的具体使用
作者:god-jiang 发布时间:2024-01-22 01:04:55
目录
前言
全局锁
表级锁
表锁
元数据锁(Metadata Locking,简称:MDL锁)
总结
参考资料
前言
在真实的企业开发环境中使用MySQL,MySQL肯定不会只有我一个人使用,而是一个团队显式的使用MySQL,或者是业务隐式的使用MySQL,那么多个用户或者客户端连接使用的时候,我们应该考虑一个问题:如果保证数据并发访问的一致性呢?这一篇我就来聊聊MySQL的锁,不涉及MySQL的事务隔离级别。
全局锁
MySQL的全局锁会关闭所有打开的表,并使全部的表处于只读状态,它们的命令为:
# 全局锁,简称FTWRL
FLUSH TABLES WITH READ LOCK;
# 解锁命令
UNLOCK TABLES;
对FTWRL进行实验:(以下的所有实验都是在MySQL8.0.22完成的)
session1 | session2 |
---|---|
FLUSH TABLES WITH READ LOCK; | |
select * from test limit 1; (正常返回结果) | |
select * from test limit 1; (正常返回结果) | |
insert into test(a,b,c) values(6,6,6); (报错) | |
insert into test(a,b,c) values(8,8,8);# sql1 (阻塞) | |
UNLOCK TABLES; | |
insert into test(a,b,c) values(8,8,8);# sql1 (session1解锁后,sql1立马执行成功) |
从以上实验可以得出:当执行FTWRL后,所有的表变成了只读状态,其他更新的操作将会被阻塞。
全局锁的主要作用就是做全库逻辑备份,也就是把数据库的每个表都select出来存成文本。
当备份过程中,整个数据库处于只读状态,风险也是及其的大。如果是在主库备份,将会导致所有的业务表都不能修改数据;如果是在从库备份,这个时候从库不能执行主库传过来的binlog,会导致主从延迟。
好在InnoDB存储引擎支持事务,mysqldump有一个参数single-transaction,可以在事务中创建一致性快照,然后进行所有表备份。在有这个参数下,备份期间可以进行数据修改,所以正常开发中建议使用InnoDB存储引擎。
表级锁
表级锁分为两种,一种是表锁,另一种是元数据锁。
表锁
表锁分为表读锁和表写锁,在MySQL的命令是:
# 表读锁
lock tables test read;
# 表写锁
lock tables test write;
接下来通过实验看下表读锁和表写锁有什么区别吧
表读锁
session1 | session2 |
---|---|
lock tables test read; | |
select * from test limit1; (正常返回结果) | |
select * from test limit 1; (正常返回结果) | |
insert into test(a,b,c) values(6,6,6); (报错) | |
insert into test(a,b,c) values(8,8,8); # sql1 (阻塞) | |
unlock tables; | |
insert into test(a,b,c) values(8,8,8); # sql1 (session1解锁后,sql1立马写入成功) |
在session1会话加上了表读锁,这个时候session1和session2都可以正常的读数据,但是session1写数据会报错,session2写数据会被阻塞,等到session1解锁了,session2的写数据才能执行成功。
从这个实验可以得出:表加上了表读锁之后,本线程和其他线程都可以读数据,本线程写数据会报错,其他线程写数据会阻塞。
表写锁
session1 | session2 |
---|---|
lock tables test write; | |
select * from test limi1; (正常返回结果) | |
select * from test limit 1; # sql1 (阻塞) | |
unlock tables; | |
select * from test limit; # sql1 (session1解锁后,sql1立马返回结果) | |
lock tables test write; | |
insert into test(a,b,c) values(6,6,6); (插入成功) | |
insert into test(a,b,c) values(8,8,8);# sql 2 (阻塞) | |
unlock tables; | |
insert into test(a,b,c) values(8,8,8);# sql2 (session1解锁后,sql2立马执行成功) |
从以上实验可以得出:表加上了表写锁之后,本线程可以进行读写操作,其他线程的读写操作都会被阻塞。
元数据锁(Metadata Locking,简称:MDL锁)
在MySQL中,数据库的DDL不属于事务范畴,如果你在session1中select一行数据,这个时候session2给这张表新增了一列xxx,这个时候可能会出现事务特性被破坏、binlog顺序错乱等bug(MySQL官网上有公布出类似的bug,感兴趣可以自行去了解)。
为了解决以上的问题,从MySQL5.5.3引入了元数据锁,MDL锁不需要显式使用,MySQL会默认加上,它的作用就是保证数据库读写正确性。以下全部用MDL表示元数据锁。
当你对一张表进行增删查改的时候会默认加上MDL读锁;当你对一张表进行表结构更改的时候会默认加上MDL写锁。
session1 | session2 | session3 | session4 |
---|---|---|---|
begin; | |||
select * from test lmi1; (正常返回结果) | |||
select * from test limit 1; (正常返回结果) | |||
alter table test add d int; (阻塞) | |||
select * from test limit 1; (阻塞) |
一开始session1会话查询test的时候,获取到了MDL读锁,可以正常查询到数据。然后session2会话查询数据也会获取MDL读锁,不冲突,也可以正常查询到数据返回。
但是到了session3会话的时候,需要获取MDL写锁,这个时候因为session1的MDL读锁没有释放,所以会阻塞。后面session4也需要MDL读锁,但是因为session3被阻塞了,所以session4也会被阻塞。
假如这是一张线上业务表,这种场景将会使后面的任何操作都失效,表现出来就是这张表变得无法写和读。如果客户端配置了MySQL重试机制的话,会在超时的时候重新建立一个session会话重新请求,然后MySQL就会因为线程不停新增而崩溃。
从上面的例子可以知道MDL锁是在语句执行的时候默认加上的,但是语句执行完是不会释放的,只有等整个事务提交了才会释放MDL锁。
所以对于我们开发者来说,在工作中应该尽量避免慢查询、尽量保证事务及时提交、避免大事务等,对于DBA来说,也应该尽量避免在业务高峰期执行DDL操作。
总结
全局锁会让所有的表变成只读状态,所有更新操作都会被阻塞
表读锁是本线程和其他线程都可以读,本线程写会报错,其他线程写会阻塞
表写锁是本线程可以读写,其他线程读写都会阻塞
引入MDL锁解决事务和DDL同时执行引发的bug
参考资料
《深入浅出MySQL》第二版:20.3.8 什么时候使用表锁
《MySQL实战45讲》林晓斌
来源:https://blog.csdn.net/weixin_37686415/article/details/114184773


猜你喜欢
- 1.regex-coach ——正则表达式工具2. IECookiesView——IE的cookie查看工具3.Flex Trace Pan
- 前言最近在用yolov5参加比赛,yolov5的技巧很多,仅仅用来参加比赛,着实有点浪费,所以有必要好好学习一番,在认真学习之前,首先向yo
- 了解blockchain的概念很简单(区块链,交易链块):它是分布式的(即不是放置在同一台机器上,不同的网络设备上的)数据库支持主办记录日益
- 我们知道 Pandas 是数据科学社区中流行的 Python 包,它包含许多函数和方法来分析数据。尽管它的功能对于数据分析来说足够有效,但定
- 简介:设计稿尺寸标注与取色专用工具,适用于设计、界面开发与网页前端安装包仅700KB,全绿色独有的双模式切换可支持双屏显示器,一面设计,一面
- 当用户访问一个网站的时候,第一屏的信息展示是非常重要的,很大程度上影响了用户是否决定停留,然而光靠文字大面积的堆积,很难直观而迅速的告诉用户
- 随着ES6规范的到来,Js中定义变量的方法已经由单一的 var 方式发展到了 var、let、const 三种之多。var 众所周知,可那俩
- 属性多层数组数据的添加修改为什么需要使用Vue.set?vue中不能检测到数组的一些变化比如一下两种:1、数组长度的变化 vm.arr.le
- 针对弹幕的爬取我们如果只需要获取看到的网页里面的而数据,使用selenium就能实现,对于直播平台来说,往往有第三方平台api让你获取数据(
- python爬虫写起来非常快,虽然也可以用java,但是没有python来的简
- MySql5.0以后均支持存储过程,最近有空,研究了一把这个。格式:以下为引用的内容:CREATE PROCEDURE
- 一、前言在Python中,除了可以自定义模块外,还可以引用其他模块,主要包括使用标准库和第三方模块。下面分别进行介绍。二、导入和使用标准模块
- 这篇文章主要介绍了如何获取Python简单for循环索引,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- DNA序列ACTGATCGATTACGTATAGTATTTGCTATCATACATATATATCGATGCGTTCAT求其互补DNA序列。在
- python发送icmp echo requesy请求import socketimport structdef checksum(sour
- cvtColor函数这个函数有两个参数1,src 要进行变换的原图像2,code 转换代码标识例子:import cv2image=cv2.
- 假如你用SQL2005做一个数据库备份,然后把这个备份到装有SQL2000的服务器去恢复,是恢复不了,同样,你把SQL2005数据库附加到S
- <style> *{position:absolute;} #panel *{border:1px so
- 1.依次安装python2和python3,并添加到系统环境变量中2.找到python3的安装目录,一般在C:\Users\Administ
- 死锁(Deadlock)所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进