MySQL锁到底锁的是什么?
MySQL的锁不是抽象概念,而是真实作用在数据结构上的控制机制:锁的对象是事务,锁的目标是数据库资源(表、页、行、间隙、元数据等)。关键在于——
Lock由InnoDB存储引擎实现,而
Latch(如
mutex、
rwlock)是更底层的内存同步机制,不归事务管理,也不参与死锁检测。初学者常把二者混淆,结果用
SHOW ENGINE INNODB STATUS查不到Latch信息,却误以为“没加锁”。
按粒度分:表锁、行锁、间隙锁、临键锁怎么选?
粒度决定并发能力,也决定你是否会被“莫名其妙卡住”:
表锁(
LOCK TABLES t1 READ/WRITE):整张表堵死,适合备份或DDL前的强制只读;但
MyISAM默认用它,
InnoDB仅在显式调用或无索引条件时退化使用
Record Lock:只锁索引记录本身,比如
WHERE id = 10(
id是主键),RR/RC隔离级别都支持
Gap Lock:锁区间,如
(5, 10)(开区间),防止幻读,**仅在RR隔离级别生效**;RC下不启用,这也是RC可能产生幻读的根本原因
Next-Key Lock:
Record Lock + Gap Lock,即
(5, 10](前开后闭),InnoDB在RR下默认行为;但遇到唯一索引等值查询(如
WHERE uniq_col = 'x')会自动优化为纯
Record Lock,不锁间隙
意向锁(IX/IS)为什么不能忽略?
意向锁是InnoDB实现多粒度加锁的“预告机制”,属于表级锁,但不阻塞读写,只阻塞冲突的表级操作。常见误区是以为“没显式加表锁就不用管它”,其实只要事务对某行加了X锁,InnoDB会自动在表上加
IX锁;此时若另一事务执行
ALTER TABLE,就会被
IX阻塞——因为
ALTER需要
S锁(共享表锁),而
IX与
S互斥。
典型现象:
ALTER TABLE t1 ADD COLUMN c1 INT卡住,查
INFORMATION_SCHEMA.INNODB_TRX发现有活跃事务,再看
INFORMATION_SCHEMA.INNODB_LOCK_WAITS,源头往往就是未提交的DML触发了
IX,拦住了DDL。
MDL锁(元数据锁)是隐形杀手
MDL锁在Server层统一管理,只要执行任何涉及表结构的操作(哪怕只是
SELECT),都会隐式加MDL读锁;而
DROP/ALTER/TRUNCATE需MDL写锁。它的坑在于:它不显示在
INNODB_LOCKS里,只出现在
performance_schema.metadata_locks(MySQL 5.7+)或
SHOW PROCESSLIST的
State字段(如
Waiting for table metadata lock)。
一个高频场景:
SELECT * FROM t1在长事务中执行后未提交,紧接着有人执行
ALTER TABLE t1 ADD INDEX——后者会一直等待,且不会被
KILL掉,直到长事务结束。这是因为MDL写锁必须等所有MDL读锁释放。
真正难调试的从来不是“有没有锁”,而是“谁在持有一个你看不见的锁,又拦住了谁”。MDL和意向锁都不出现在传统InnoDB锁视图里,却常常是线上DDL卡死、慢查询堆积的根因。
