MySQL的全局锁和表级锁的具体使用

 更新时间:2021年08月20日 12:54:01   作者:god-jiang  
在真实的企业开发环境中使用MySQL,我们应该考虑一个问题:如果保证数据并发访问的一致性呢?这一篇我就来聊聊MySQL的锁,感兴趣的可以了解一下

前言

在真实的企业开发环境中使用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讲》林晓斌

到此这篇关于MySQL的全局锁和表级锁的具体使用的文章就介绍到这了,更多相关MySQL 全局锁和表级锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mysql锁表确认及解除锁表的实现示例

    mysql锁表确认及解除锁表的实现示例

    使用MySQL数据库时,我们可能会遇到数据库表被锁定的情况,本文主要介绍了mysql锁表确认及解除锁表的实现示例, 具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • MySQL中批量删除指定前缀表的sql语句

    MySQL中批量删除指定前缀表的sql语句

    有时候我们在安装一些cms的时候,这些cms都是带表前缀的方便区分数据,但有时候我们测试完需要删除的时候又有别的前缀表就可以参考下面的方法
    2013-06-06
  • 使用MySQL如何实现分页查询

    使用MySQL如何实现分页查询

    这篇文章主要介绍了使用MySQL如何实现分页查询,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • MySQL 索引分析和优化

    MySQL 索引分析和优化

    MySQL 索引分析和优化...
    2006-12-12
  • MySQL中查询当天数据中离时间点最近的数据(两种方法)

    MySQL中查询当天数据中离时间点最近的数据(两种方法)

    在 MySQL 中,你可以使用 ORDER BY 和 LIMIT 语句来查询当天数据中离指定时间最近的数据,本文给大家介绍MySQL中查询当天数据中离时间点最近的数据,感兴趣的朋友一起看看吧
    2023-12-12
  • MYSQL代码 定期备份Mysql数据库

    MYSQL代码 定期备份Mysql数据库

    Mysql自动备份脚本供大家参考,实现了定期备份Mysql数据库,并且可以选在在每周的一天做指定目录下文件的全面备份,备份文件自动上传到你指定的FTP上,保证了备份的可靠性。
    2009-04-04
  • 将json文件数据导入到MySQL表中的详细教程

    将json文件数据导入到MySQL表中的详细教程

    如何使用json文件将数据导入到MySQL数据库中的表里?Excel表格等文件的数据通过java或者python等语言读取后生成一个json文件,然后想要将文件中的数据写入到MySQL表中,本文介绍了将json文件数据导入到MySQL表中的详细教程,需要的朋友可以参考下
    2024-07-07
  • MySQL EXPLAIN执行计划解析

    MySQL EXPLAIN执行计划解析

    本文主要介绍了MySQL EXPLAIN执行计划解析,通过MySQL EXPLAIN执行计划的各个字段的含义以及使用方式。感兴趣的小伙伴可以参考一下
    2022-08-08
  • MySQL数据被误删的解决方法

    MySQL数据被误删的解决方法

    之前被要求开发一个OA项目,需求还要及时生效(一边开发一边使用),有一次生产环境的一个bug本地没办法复现,在调试的过程中,我俩当作开发环境很自然的把数据给删了,所以在这里记录一下MySQL数据备份和恢复的方法及操作,希望可以帮助到跟我一样的小伙伴
    2024-01-01
  • MYSQL锁表问题的解决方法

    MYSQL锁表问题的解决方法

    这篇文章主要介绍了MYSQL锁表问题的解决方法,结合实例形式分析了MySQL锁表问题的常见情况与相应解决方法,需要的朋友可以参考下
    2016-03-03

最新评论