死锁是怎么发生的?SELECT ... FOR UPDATE 到底锁了什么?本文系统梳理 MySQL 的锁体系。

一、锁的分类总览

  • 1.1 按粒度——全局锁、表级锁、行级锁
  • 1.2 按模式——共享锁(S)、排他锁(X)、意向锁(IS/IX)
  • 1.3 按算法——记录锁、间隙锁、临键锁

二、全局锁

  • 2.1 FLUSH TABLES WITH READ LOCK——全库只读
  • 2.2 使用场景——全库备份(mysqldump --master-data
  • 2.3 风险——业务停摆

三、表级锁

  • 3.1 表锁——LOCK TABLES ... READ/WRITE
  • 3.2 元数据锁(MDL)——DDL 操作自动加锁
  • 3.3 MDL 的坑——ALTER TABLE 阻塞所有查询
  • 3.4 自增锁(AUTO-INC)——innodb_autoinc_lock_mode

四、行级锁

  • 4.1 记录锁(Record Lock)——锁定索引记录
  • 4.2 间隙锁(Gap Lock)——锁定记录之间的间隙
  • 4.3 临键锁(Next-Key Lock)——记录锁 + 间隙锁
  • 4.4 插入意向锁(Insert Intention Lock)

五、意向锁

  • 5.1 为什么需要意向锁——表锁和行锁的冲突检测
  • 5.2 加行锁前先加意向锁——IS / IX
  • 5.3 意向锁之间不冲突

六、死锁排查

  • 6.1 SHOW ENGINE INNODB STATUS——死锁日志分析
  • 6.2 死锁的四个必要条件
  • 6.3 常见死锁场景——两个事务以不同顺序加锁
  • 6.4 死锁避免——统一加锁顺序、缩短事务

七、乐观锁与悲观锁

  • 7.1 悲观锁——SELECT ... FOR UPDATE
  • 7.2 乐观锁——版本号 CAS
  • 7.3 适用场景——冲突多的用悲观锁,冲突少的用乐观锁

八、总结

  • MySQL 锁体系全景图
  • 锁等待超时——innodb_lock_wait_timeout