全局锁仅适用于离线从库逻辑备份,线上禁用;表级锁分手动锁、MDL、意向锁三类;InnoDB行锁实为临键锁组合,含记录锁与间隙锁;S/X锁是底层语义,可作用于表或行粒度。

全局锁只在备份时用,但线上千万别直接上
全局锁本质是让整个 MySQL 实例变成只读,命令就是 FLUSH TABLES WITH READ LOCK。它会阻塞所有 DML(INSERT/UPDATE/DELETE)和 DDL(ALTER/DROP),连事务提交都卡住——不是“慢”,是彻底挂起。
- 真实场景只适合离线从库做逻辑备份,且必须配合
mysqldump --single-transaction这类无锁方案优先考虑 - 主库执行等于停业务;从库执行会堆积 binlog,导致主从延迟飙升
- 加锁后若客户端异常断开,锁不会自动释放,得靠 DBA 手动
UNLOCK TABLES或杀连接
表级锁分三类:手动表锁、MDL、意向锁,别混为一谈
表级锁听着简单,实际包含三套完全不同的机制:
-
LOCK TABLES t1 READ是 Server 层显式锁,不依赖引擎,MyISAM 和 InnoDB 都认,但业务中几乎不用——它不兼容事务,且会阻塞其他会话的写,甚至阻塞同一会话后续对其他表的写操作 - 元数据锁(
MDL)是自动加的,你执行SELECT就悄悄持有一个共享 MDL 锁,而ALTER TABLE必须等所有 MDL 共享锁释放才能拿到排他锁;常见卡顿就是“查着查着,DDL 一直等” - 意向锁(
IS/IX)是 InnoDB 内部用的“预告信号”:比如你要给某行加 X 锁,InnoDB 会先在表上加IX锁,这样别的事务想对整张表加表级写锁时,立刻就知道“有人正在动行”,不用逐行检查
行级锁不是一种锁,而是记录锁 + 间隙锁 + 临键锁的组合拳
InnoDB 的“行锁”其实是动态策略:在 REPEATABLE READ 隔离级别下,默认用的是 Next-Key Lock(临键锁),即记录锁 + 它左边的间隙锁合体。这意味着:
-
SELECT * FROM users WHERE id = 5 FOR UPDATE不只锁住 id=5 这一行,还会锁住 (3,5) 这个间隙(假设前一条是 id=3) -
SELECT * FROM users WHERE id > 10 FOR UPDATE会锁住所有 id>10 的记录,以及它们之间的所有间隙,甚至可能锁住“无穷大”之后的插入点 - 间隙锁(
Gap Lock)本身不锁记录,只防插入,所以SELECT ... FOR SHARE在 RR 级别下也可能触发间隙锁,不是只有FOR UPDATE才有
共享锁和排他锁是行为本质,不是独立类型
S 锁 和 X 锁 是所有锁的底层语义:S 锁允许多个并发读,但会阻塞 X 锁;X 锁是独占的,会阻塞所有 S/X 锁。关键点在于它们可作用于不同粒度:
- 表级 S 锁 →
LOCK TABLES t1 READ;表级 X 锁 →LOCK TABLES t1 WRITE - 行级 S 锁 →
SELECT ... LOCK IN SHARE MODE(MySQL 5.7+)或SELECT ... FOR SHARE(8.0+) - 行级 X 锁 →
SELECT ... FOR UPDATE,或任何UPDATE/DELETE语句隐式持有 - 注意:
INSERT不走记录锁,而是先申请Insert Intention Lock(插入意向锁),再和间隙锁协调——这也是为什么两个事务同时往同一间隙插不同值,通常不冲突
真正容易被忽略的,是锁的“自动升级”和“隐式持有”:比如一个 UPDATE 没走索引,InnoDB 可能从行锁退化成全表扫描+表级锁;又比如事务里只执行了 SELECT ... FOR UPDATE 却忘了 COMMIT,那 X 锁就一直挂着,别人一碰那行就卡死。锁不是配置项,是运行时状态,得看 INFORMATION_SCHEMA.INNODB_TRX 和 INNODB_LOCK_WAITS 才能看清真相。










