前阿里数据库专家总结的MySQL里的各类锁(上篇)

0.前言

MySQL按照加锁的范围,分为全局锁、表级锁、行级锁。git

本文做为上篇,主要介绍MySQL的全局锁 和 表级锁。github

重要的实战总结为,如何安全地变动一个表的表结构。面试

1.全局锁

定义:数据库

全局锁就是对整个数据库实例加锁。安全

全局锁语法:session

Flush tables with read lock (FTWRL)线程

当你使用这个命令后,整个库处于只读状态,以后其余线程的数据更新语句(DML)、数据定义语句(DDL)都会被阻塞。orm

场景:不支持事务的引擎(如MyISAM),作全库的逻辑备份。blog

不过咱们通常使用innodb,这个锁不太会接触,就不展开详细介绍了。队列

2.表级锁

表级锁其实有两种,一种叫表锁,一种叫原数据锁(meta data lock, MDL)

2.1 表锁

表锁的语法是:

锁表:lock tables … read/write

释放锁: unlock tables 主动释放锁

表锁也可以在客户端断开的时候自动释放。

值得注意的是,lock tables 除了会限制别的线程的读写外,当前线程接下来的操做也会被限制。

一样的,对于innoDB这种支持行锁的引擎,咱们通常也不会去使用用表锁,所以,这部份内容也只须要简单了解下便可。

2.2 MDL锁

原数据锁meta data lock 也是一种表级锁,在 MySQL 5.5 版本中引入。

当咱们对一个表作CRUD操做的时候,会加 MDL 读锁;当要对表作结构变动操做的时候,加 MDL 写锁。

 

前阿里数据库专家总结的MySQL里的各类锁(上篇)

MDL读写锁的互斥

  • 读锁之间不互斥,因此咱们能够有多个线程同时对一张表增删改查。
  • 读锁和写锁之间、写锁和写锁之间是互斥的,用来保证变动表结构操做的安全性。所以,只要有一个线程要对一个表加字段,那天其余线程必须等这个线程完成表结构变动之后才能执行。

看到这里,不得不给你们举例一个平常会踩的坑。

对于大表DDL,你们通常比较谨慎,而对于小表,就会比较随意。可是小表DDL也能形成数据库崩溃。

前阿里数据库专家总结的MySQL里的各类锁(上篇)

Session A第一个启动,开启事务,select后没有马上commit,模仿一个长事务,此时,session A对表tt的MDL读锁尚未释放。

Session B以后执行一个select,因为MDL读锁之间不互斥,所以执行成功。

Session C以后想对表tt 执行一个alter语句,须要得到MDL写锁,可是因为Session A持有了MDL读锁,读写锁互斥,所以Session C被阻塞。

Session D这时候也想执行一个select,因为Session C被阻塞,因此Session D也会被阻塞。

因此这个时候,后续的线程就都没法读写了。

若是接下来这个表上有频繁的查询,并且客户端有重试机制,那么超时后会再起一个新的session来查询,很快数据库的线程就溢出了。

这里有几个小问题须要稍微再解释一下:

1)从Session A的状况咱们得知,事务中 的MDL锁,在语句开始时申请,可是并非在语句结束后立刻释放的,而是在整个事务提交后才会释放。

2)SessionC(DDL操做)被前面的SessionA和B(查询操做,获取MDL 读锁)所阻塞,这里实际上并无成功获取MDL写锁,为何Session D的读操做会被sessionC所阻塞呢?这里的缘由是,MySQL Server端,对于Session C和Session D会有一个队列来决定谁先执行。

看到这里,我相信确定有对MySQL比较熟悉的朋友会问了,MySQL 5.6不是号称支持Online DDL吗?怎么这里又会有各类阻塞呢?

首先,咱们先明确下什么叫作Online DDL。

Online DDL的过程当中,对于锁的获取分为五步(具体online DDL过程比较复杂,本文不展开说明):

1)拿到MDL写锁

2)降级成MDL读锁

3)真正作DDL

4)升级成MDL写锁

5)释放MDL锁

一、二、四、5若是没有锁冲突,执行时间都是很是短的。绝大部分时间是第三步占用了,而这个期间,表可用正常读写,因此被称为Online DDL。

而咱们上文的例子,其实是在第一步就阻塞了。

3.So,如何作一次安全的表结构变动

其实,不管大表小表的表结构变动,都应用引发咱们重视。

总结了上文,你们应该都知道了最关键的三点:

避免长事务!

避免长事务!

避免长事务!

尤为是在执行表结构变动前,能够在information_schema库的innodb_trx表中,查看当前执行的事务。若是有长事务正在执行,要延迟等待执行变动,或者手动先kill长事务。

另外,尽可能保证表结构变动在数据库流量低峰期操做,好比夜间,这样能更好地避免出现风险。

因此,如何作一次安全的表结构变动?

1)避免长事务

2)在流量低峰进行

就是这么简单。

 

下一期,咱们就好好聊聊 行锁,不见不散~

 

参考:

丁奇《MySQL 实战45讲》

 

看到这里了,原创不易,点个关注、点个赞吧,你最好看了~

知识碎片从新梳理,构建Java知识图谱:https://github.com/saigu/JavaKnowledgeGraph(历史文章查阅很是方便)

扫码关注个人公众号“阿丸笔记”,第一时间获取最新更新。同时能够免费获取海量Java技术栈电子书、各个大厂面试题。

阿丸笔记

相关文章
相关标签/搜索