前言
这里假设我们都知道mysql5.7在DDL时,哪些操作不会阻塞读写、哪些操作会阻塞(不知道的童鞋可以先学习5.7DDL原理)。那么这里存在一个问题,若DDL开始的时候,操作的表已经有事务在占用了,会发生什么?带着这个疑问,一起来上机实验,来探索背后的流程余原理。
测试
知识回顾:Copy模式的DDL会阻塞其他会话对变更表的写操作,并会复制表。
申明:事务隔离级别为RC。
实验以修改类型为例:alter table t2 modify c2 c2 varchar(10);
测试流程表如下:
上述实验细节:
- S2是一直被S1中的查询事务所阻塞,这是因为MDL的缘故
- S3一直被S2中的alter操作所阻塞,也是在等MDL
- 当S1提交时,S2能很快完成,S3在S2后才完成,这是因为S2的alter操作虽然被阻塞,但内部已经执行了数据”copy”的操作,只需等待S1提交,然后获取t2表的MDL,即可完成后续的”收尾”工作,
对应锁的流程图如下:
可以看到,若在DT2与DT4之间,S1中再执行一个当前读的SQL,即需要申请X锁(这里我们不关注是表上还是记录上的X锁),那么即会产生死锁(这种死锁信息在show engine innodb status中看不到)。
可以想到,造成死锁的原因包含如下:
1.早事务是select,只获得了表上MDL,没获取S锁
2.后面的alter操作获取了表的S锁
结论
alter操作开始前的事务已经获得表中的S/X锁,而不仅仅是MDL,则事务不会发送死锁而回退。—innodb处理死锁是选择回滚开销小的事务。