LOCK TABLES … READ 是表级读锁,仅锁定显式指定的表,允许多个会话共享读锁但排斥写锁及DDL;FLUSH TABLES WITH READ LOCK 是全局读锁,阻塞所有库表的写操作与DDL,用于物理备份一致性快照。

LOCK TABLES … READ 是表级读锁,只锁指定表
它只作用于你明确列出的表,比如 LOCK TABLES t_user READ,其他没被列出来的表完全不受影响。多个会话可以同时对同一张表加 READ 锁(共享),但只要有一个 READ 锁存在,任何会话都加不了 WRITE 锁。持有锁的会话自己也不能写这张表,也不能做 ALTER/DROP 等 DDL 操作。
常见错误现象:UPDATE t_user SET name='x' WHERE id=1 报错 Table 't_user' was locked with a READ lock and can't be updated;或者执行 ALTER TABLE t_user ADD COLUMN x INT 时卡住不动——不是死锁,是被表锁阻塞了。
释放方式只有两种:UNLOCK TABLES,或客户端断开连接。注意:事务提交或回滚不会释放它。
FLUSH TABLES WITH READ LOCK 是全局读锁,锁所有表
不带表名时,FLUSH TABLES WITH READ LOCK 会关闭所有打开的表,并对整个实例中所有数据库的所有表加全局读锁。效果等同于“整个 MySQL 变成只读”,所有写操作(INSERT/UPDATE/DELETE)、所有 DDL(ALTER/DROP/TRUNCATE)全部被阻塞,连 CREATE DATABASE 都不行。
容易踩的坑:
- 如果当前有长事务未提交(比如一个
BEGIN; UPDATE ...没COMMIT),FTWRL 会一直等待,导致备份脚本卡死 - 它会阻塞所有写,包括业务写入和后台运维操作,生产环境执行前必须确认低峰期
-
UNLOCK TABLES能释放它,但仅限于同一个会话;换一个会话执行UNLOCK TABLES没用
二者锁粒度与兼容性完全不同
LOCK TABLES 是显式表锁,属于 MySQL Server 层的锁机制,InnoDB 表上使用它会绕过事务隔离层,破坏 MVCC 行为,可能导致一致性问题。而 FLUSH TABLES WITH READ LOCK 在加锁前会先等所有活跃事务(尤其是未提交的 DML)结束,确保拿到的是“一致快照”——这也是为什么它常被 mysqldump --lock-all-tables 内部调用。
关键差异点:
-
LOCK TABLES t1 READ, t2 WRITE支持混合锁类型;FTWRL 不支持指定表,只能全库锁(除非用FLUSH TABLES t1, t2 WITH READ LOCK,但这是 5.7.23+ 才支持的语法,且仍需满足无活跃事务) - FTWRL 会阻塞 MDL 写锁请求(如 DDL),而普通
LOCK TABLES不影响其他表的 MDL - FTWRL 下,
SELECT日志、慢日志等系统表仍可写入;LOCK TABLES对这些表无影响(它们本来就不在你的锁列表里)
什么时候该用哪个
绝大多数场景下,别手动用 LOCK TABLES ——InnoDB 表用它等于自废事务武功,容易引发隐性冲突。真要锁表,优先考虑行锁(SELECT ... FOR UPDATE)或应用层协调。
FLUSH TABLES WITH READ LOCK 基本只剩一个正当用途:配合文件系统快照做物理备份(如 LVM/ZFS snapshot),且必须确保没有长事务。现在更推荐用 mysqldump --single-transaction(InnoDB 专用)或 Percona XtraBackup。
真正容易被忽略的点:两者都会被正在执行的 DDL 阻塞,而 DDL 又会被长事务阻塞——三层等待链一拉就崩。查锁状态永远从 SHOW PROCESSLIST + SELECT * FROM performance_schema.metadata_locks 入手,别只盯着 INFORMATION_SCHEMA.INNODB_TRX。


















