在读本文章前,您需要知道如下知识点
- 数据库的元数据锁
- 锁会在队列中等待其他锁的释放
- alter table的一些语法
- 为啥我们需要在生产环境去修改列名,修改索引(非主键),增加索引(非主键),删除索引(非主键)
当然不知道也没关系,我们也会讲到这个知识。
一·元数据锁
首先确定什么是元数据锁
另一类表级的锁是 MDL(metadata lock)。MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的
元数据锁是server层面的锁,也是表级锁,主要分为如下两类:
- 元数据读锁,在DML时(insert,delete,update,select)时加该锁
- 元数据写锁,在DDL时加(alter table,drop index ,修改列名等等操作)
重点:如下结论非常重要!!!
元数据锁读读共享,读写互斥,写写互斥,申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。
对上述结论的解释:
- 读读共享: 读锁和读锁之间是不冲突的,例如你去select t2 这个表,其他人依然可以去insert 或者delete,这个很好理解。
- 读写互斥:读锁和写锁之间互斥,例如你在select * from t2 ,而另一个人在drop table t2 ,那到底是你先读数据还是他先删除表呢?
- 写写互斥: 例如你在对一个列名rename,另一个人也在对同样的列名rename ,那么数据库需要以那个为准呢?
- 一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作:此类事情经常会报错的信息为:Waiting for table metadata lock,意味着有元数据锁还未释放,甚至还没有获取到,你剩下的查询,或者写入操作全部会被阻塞,假如是在生产环境,这个将是灾难性的。
二·做实验
- 实验一:先加元数据读锁,再加写锁,再加读锁。
image.png
image.png
在alter 操作阻塞时,我们再执行一下查询sql
select * from t2;
然后就有2个阻塞的记录了
image.png
如上实验结论:
数据库有事务在查询或者写入某个表,但是还没有提交事务,你这个时候去alter table 则你这个alter操作将被阻塞,然后后续的查询操作也将被阻塞,假如你的这个alter table操作很久时间,那么后续的查询都需要等你,有时候千万级别的表 alter 操作很耗时的,所以这样对于生产环境而言肯定是不行的,后端开发可能获取到如下错误信息 Error Code: 2013. Lost connection to MySQL server during query
- 实验二:先加元数据写锁,再加读锁
这个实验就尴尬了 ,我执行如下操作:
begin; #显式开启事务
alter table t2 change column b newb int(11); #进行alter操作
但是我没有commit 按道理说此时这个元数据写锁应该未释放,但是在另一个会话中,
select * from t2;
不阻塞,直接查询出数据了,那位大佬可以解释一下该情况,有点懵逼~
三·在线DDL /online ddl
我发现对在线DDL理解错了,我需要再看看文档才能写完这个文章。以及解决一下为啥元数据读锁我没有提交事务,就释放的问题。
网友评论