基础材料:
centos7.5 mysql 5.7.24
前一篇说明了元数据锁的相关加锁顺序,今天再结合online DDL更深入的研究一下这个加锁顺序究竟如何。
这里先简单说明一下online DDL锁升降级的过程,大体分为三步:
1、准备阶段:将申请到的SHARED_UPGRADABLE读锁升级为EXCLUSIVE写锁。禁止读写。
2、执行阶段:将EXCLUSIVE写锁降级成SHARED_UPGRADABLE读锁。期间可读写。
3、提交阶段:将SHARED_UPGRADABLE读锁升级为EXCLUSIVE写锁。禁止读写。
下面进行一个实验,用来毁三观,将
id 41 | id 42 | id 43 | id 44 | id 45 |
begin; | begin; | alter table testok add z varchar(10) not Null; | begin; | |
select * from testok limit 1; | select * from testok limit 1; | select * from testok; |
此时提交id 42,43,后会发现id 45的语句执行完了,id 44仍然被卡住等待EXCLUSIVE写锁,和开始一样一点没变。话说之前写的可是,写锁优先,且阻塞后续操作的啊,为啥id 45先执行了,44没动,这是不是有问题?
首先说明前面说的加锁规则并没有问题,当id 42,43执行完成后,id 44确实执行了,会在准备阶段拿到EXCLUSIVE写锁,此时id 45被pending。但在id 44执行阶段会进行锁降级,同为读锁,则id 45可以获取该锁,且持有该锁。当id 44运行到了提交阶段,要进行锁升级,此时需要等待id 45的读锁释放,被pending。观察的直观现象就是id 45执行完了,id 44好像没动。
如果id 45 执行的是lock tables testok read;select ....lock in share mode;select...for update则表现的情况与上面相同。
如果id 45 执行的是lock tables testok write;则id 44先执行完成并提交,id 45使用排他锁锁住该表。
如果id 45 执行的是alter table xxx,则id 45一直等待id 44的SHARED_UPGRADABLE锁释放,直到id 44执行完成。