王小川|MySQL强人“锁”难《死磕MySQL系列 三》( 三 )


回答是:“MDL 是在事务提交后才会释放 , 这意味着事务执行期间 , MDL 是一直持有的 。 ”
那么看一个场景 。
首先 , 线程A开启事务并执行查询语句时 , 对表加上了MDL锁 。
然后 , 线程B执行的是查询 , 并不会堵塞住 , 因为读与读并不冲突 。
接着 , 线程C修改表结构 , 此时的线程A还未提交事务 , MDL还未释放 , 这时的线程因无法获取到MDl写锁 , 就会被阻塞 。
最后线程D执行查询会发生什么呢?
答案是堵塞 。
【王小川|MySQL强人“锁”难《死磕MySQL系列 三》】到这里按照正常的逻辑 , 线程C没有获取到MDL的写锁 , 线程D是可以申请到MDL读锁的 , 那为什么还会堵塞呢!
这是因为申请MDL锁的操作会形成一个队列 , 队列中写锁获取优先级高于读锁 , 一旦出现MDL写锁等待 , 会阻塞后续该表的所有CURL操作
到这里你有没有后背发凉 , 一旦你在一个未提交事务之后执行了DDL操作 , 那么等到的结果就是MySQL挂掉 , 客户端会有重试机制 , DDL后所有CURD会在超时后重新发起请求 , 这个库的线程会很快爆满 。
既然这样如何给表安全的执行DDL操作呢?
首先 , 必须解决到长事务 , 事务不提交MDL锁就无法释放 。
然后 , 在MySQL系统表里找到infomation_schema库中的innodb_trx , 可以查看当前正在执行中的事务ID , 这个表在事务那期文章中也没少提 。
接着 , 你是不是想kill掉这些长事务然后执行DDL不就得了 。
试想一下 , 当你kill掉的下一刻一个新的事务又进来了 , 同时你又执行了DDL操作 , 后果是什么应该清楚了哈!这种操作肯定是不行的 。
官方大大怎么会允许这种情况发生呢!
于是当你执行DDL操作时alter table kaka wait 30 add name可以加一个等待时间 , 如果在这个等待时间拿到MDL写锁最好 , 拿不到也不能堵塞后边的业务逻辑 , 先放弃 。 再重试执行这个命令 。
四、总结


坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念 。 愿文章在偌大的互联网上能给你带来一点帮助 , 我是咔咔 , 下期见 。