表锁
lock tables … read/write; unlock tables 主动释放锁,也可以在客户端断开的时候自动释放
对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。
元数据锁(meta data lock MDL)
MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。MDL等到事务提交才会释放
MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁
读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查
读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性
example 给小表加字段导致整个库挂了
session A 先启动,这时候会对表 t 加一个 MDL 读锁
session B 需要的也是 MDL 读锁,因此可以正常执行
session C 会被 blocked,是因为 session A 的 MDL 读锁还没有释放
之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞
如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新 session 再请求的话,这个库的线程很快就会爆满
如何安全给小表加字段
首先我们要解决长事务,事务不提交,就会一直占着 MDL 锁
在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务
在 alter table 语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程。