必须用flush tables with read lock的唯一情形是:库中存在myisam等非事务表且进行全库逻辑备份;此时--single-transaction失效,备份可能跨表不一致,又无法转引擎或换工具。

MySQL中全局读锁 FLUSH TABLES WITH READ LOCK(FTWRL)不是“让数据库变慢”的开关,而是为全库逻辑备份强行制造一致性视图的兜底手段——它有效,但代价高;能用,但应尽量避免。
什么时候必须用 FLUSH TABLES WITH READ LOCK
核心判断依据只有一条:库中存在不支持事务的表(如 MyISAM、MEMORY 等引擎),且你正在做全库逻辑备份(比如用 mysqldump 导出 SQL 文件)。
-
mysqldump --single-transaction依赖 MVCC 和可重复读隔离级别,仅对InnoDB表生效;一旦库中混有MyISAM表,该参数会静默失效,备份结果可能跨表不一致(例如账户扣款了但订单没生成) - 你无法临时把所有表转成
InnoDB(比如表太大、业务不允许锁表、或依赖MyISAM的全文索引特性) - 你使用的备份工具不支持事务快照(如某些自研脚本、老版本
mysqldump或非官方工具)
FLUSH TABLES WITH READ LOCK 和 SET GLOBAL readonly = true 别混用
两者都能让全库只读,但行为和风险完全不同:
-
FLUSH TABLES WITH READ LOCK是会话级命令,客户端异常断开后 MySQL 自动释放锁,数据库恢复可写 -
SET GLOBAL readonly = true是全局变量修改,异常断连不会自动回滚;若未手动执行SET GLOBAL readonly = false,库将长期处于不可写状态 - 很多高可用系统(如 MHA、Orchestrator)用
readonly值判断主从角色,随意修改可能触发误切换 -
FLUSH TABLES WITH READ LOCK还会阻塞COMMIT,而readonly不阻塞已开启事务的提交,语义更严格
实际执行时最容易卡住的三个点
FTWRL 不是“一敲就锁”,它在内部要串行完成多个步骤,任一环节被阻塞都会让命令 hang 住:
- 等待所有活跃事务释放
MDL(元数据锁):如果此时有长事务正在执行ALTER TABLE或大查询,FTWRL 会一直等 - 等待所有表的文件描述符(fd)关闭:若某张表正被
SELECT INTO OUTFILE或其他进程打开,也会卡住 - 等待
COMMIT锁:如果有事务正处于PRECOMMIT阶段(比如两阶段提交中的 XA 事务),FTWRL 会阻塞直到其完成 - 验证方式:执行
SHOW PROCESSLIST,看是否有线程状态为Waiting for global read lock
备份完成后别忘了 UNLOCK TABLES
很多人加完锁开始跑 mysqldump,却忘了最后一步释放:
-
UNLOCK TABLES必须由同一个连接执行,不能换会话 - 如果使用脚本自动化,务必确保即使
mysqldump失败也要执行UNLOCK TABLES(建议用trap或 try/finally 逻辑包裹) - 忘记解锁的后果不是“慢”,而是整个库持续只读——所有
INSERT/UPDATE/DELETE和 DDL 全部阻塞,业务直接中断
真正棘手的不是 FTWRL 怎么用,而是它暴露的问题:为什么库中还有非事务表?为什么备份流程没做引擎检查?为什么没有提前识别出长事务?这些比锁本身更值得花时间解决。











