全局锁就是对整个数据库实例加锁。MySQL提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括 建表、修改表结构等)和更新类事务的提交语句。
- 全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都select出来存成文本。
坏处:
如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
如果你在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。
如果不加锁:
备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。
但是这个可以用事务来解决,确保在备份的时候也可以更新。
官方自带的逻辑备份工具是mysqldump。当mysqldump使用参数–single-transaction的时候,导 数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是 可以正常更新的。只适用于支持事务的引擎!
为什么不用set global readonly=true?
- 在有些系统中,readonly的值会被用来做其他逻辑,比如用来判断一个库是主库还是备 库。
- 二是,在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么 MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态。
MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。
表锁的语法是 lock tables …read/write。用unlock tables主动释放锁, 也可以在客户端断开的时候自动释放。
如果在某个线程A中执行lock tables t1 read, t2 write; 这个语句,则其他线程写t1、读 写t2的语句都会被阻塞。同时,线程A在执行unlock tables之前,也只能执行读t1、读写t2的操 作。连写t1都不允许,自然也不能访问其他表。
另一类表级的锁是MDL(metadata lock)。不需要显式使用。当对一个表做增删改查操作的时候,加MDL读锁;当 要对表做结构变更操作的时候,加MDL写锁。
MDL不好的地方:
session c被 a 阻塞,之后所有要在表t上新申请MDL读锁的请求也 会被session C阻塞。整个表完全不可读写。如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新session 再请求的话,这个库的线程很快就会爆满。
所以如何安全的给小表加字段?
- kill掉长事务
- 要是请求频繁怎么办?alter table语句里面 设定等待时间,如果在这个指定的等待时间里面能够拿到MDL写锁最好,拿不到也不要阻塞后 面的业务语句,先放弃。



