本文中的所有内容基于存储引擎为 InnoDB。
全局锁就是对整个 MySQL 实例加锁,MySQL 提供的命令为 Flush tables with read lock(下文缩写为 FTWRL)。
当需要整个库是只读状态时可以用这个命令。使用了这个命令后,其他线程的以下语句会被阻塞:
典型的使用场景是做全库逻辑备份,但是有两个缺点:
简单说下 MySQL 备份:官方自带的工具是 mysqldump,可以使用参数 –single-transaction 来开启新的事务,拿到最新的视图(只支持有事务机制的引擎,MyISAM 不支持)。
不使用 set global readonly=true 的原因:
- readonly 有其它用途,比如判断主库还是备库
- FTWRL 会在客户端出异常的时候自动释放,实例会恢复到之前的状态。readonly 不会,除非再次设置,在未重新设置期间全库不可写。
命令是 lock tables … read/write,可以使用 unlock table 主动释放也可以类似 FTWRL 自动释放。
如果在 A 线程执行 lock tables t1 read, t2 write,造成的影响如下:
MDL(metadata lock,元数据锁),不需要显式使用,访问的时候会自动加上,事务提交后自动释放。
对表数据增删改查的时候,加 MDL 读锁;对表结构进行变更,加 MDL 写锁。
规则是:读锁之间不互斥,读写锁和写锁互斥,保证变更表结构操作的安全性。

session A 启动后,session B 可以正常读,session C 的 DDL 语句会被阻塞。为什么 session D 语句也会被阻塞呢?这是因为 session C 的被阻塞,之后对表添加的 DML 读锁也会被阻塞。
那么我们怎么给表加字段呢:
ALTER TABLE tbl_name NOWAIT add column 或 ALTER TABLE tbl_name WAIT N add column 语句。MyISAM 不支持行锁
行锁指表中一行数据或者一行记录的锁。
在 InnoDB 事务中,行锁是在需要的时候加上,事务结束或者提交才释放(两阶段锁协议)。期间其它事务如果想更新相关行会被阻塞。
启发:如果事务需要锁多行,要把可能造成锁冲突影响并发度的锁往后放。