mysql中的锁机制:行级锁与表级锁

11次阅读

InnoDB支持行级锁而MyISAM仅支持表级锁;行锁实际作用于索引记录,无索引时会退化为表锁;死锁自动检测并回滚,需通过SHOW ENGINE INNODB STATUS或开启innodb_print_all_deadlocks分析。

mysql中的锁机制:行级锁与表级锁

行级锁只在 InnoDB 有效,MyISAM 根本不支持

mysql 的锁机制和存储引擎强绑定。InnoDB 支持行级锁(select ... for UPDATEUPDATEdelete 等语句默认加行锁),而 MyISAM 只支持表级锁(所有 DML 操作都锁整张表)。如果你执行了 SELECT ... FOR UPDATE 却没生效——先查 SHOW CREATE table tbl_name,确认引擎是不是 ENGINE=InnoDB

常见错误现象:

  • 在 MyISAM 表上执行 SELECT ... FOR UPDATE 不报错,但实际无锁效果(语句成功,锁未建立)
  • 事务中更新某几行后,其他事务仍能修改同一张 MyISAM 表的任意行(因为根本没行锁)
  • 误以为加了索引就自动用行锁——其实 InnoDB 行锁是加在索引记录上的,若 WHERE 条件无法命中索引,会退化为表级锁(锁全表所有索引项,等效于锁表)

行锁不是“锁住某行数据”,而是锁住索引记录

InnoDB 的行级锁本质是锁住聚簇索引或二级索引中的记录。这意味着:

  • UPDATE users SET name='a' WHERE id = 100:如果 id 是主键,则锁住聚簇索引中 id=100 的那条记录
  • UPDATE users SET name='a' WHERE email='x@y.z':如果 email 有唯一索引,则锁住该二级索引记录 + 对应的聚簇索引记录(next-key lock)
  • UPDATE users SET name='a' WHERE status = 1:若 status 无索引,InnoDB 会扫描全表,对每条匹配记录加锁,同时可能触发间隙锁(gap lock)或临键锁(next-key lock),导致大量无关行被锁定

容易踩的坑:用 EXPLAIN 看执行计划,确认 type 是否为 const/ref;如果是 ALLindex,大概率已丧失行锁粒度。

表级锁不只是 LOCK TABLES,隐式锁更常见

显式表锁(LOCK TABLES t1 WRITE)极少在业务代码中使用,但隐式表级锁频繁出现:

  • ALTER TABLE 在大多数 MySQL 版本中会获取元数据锁(MDL),阻塞后续 DML,本质是表级协调锁
  • MyISAM 执行 INSERT 时自动加表写锁,此时任何读(SELECT)都会等待
  • InnoDB 在某些 DDL 场景下(如无 ALgoRITHM=INPLACE 的列添加)也会升级为表级锁
  • FLUSH TABLES WITH READ LOCK 是全局表级读锁,常用于物理备份,但会阻塞所有写入

性能影响明显:一个慢 ALTER TABLE 可能让整个库的写请求排队,监控时注意 show processlist 中状态为 Waiting for table metadata lock线程

死锁检测与日志怎么看

InnoDB 死锁检测是自动开启的(innodb_deadlock_detect=ON),一旦发生,MySQL 会选一个事务回滚并返回错误:

Error 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

要定位原因,必须开死锁日志:

  • 设置 innodb_print_all_deadlocks = ON(写入 error log,非实时输出)
  • 或执行 SHOW ENGINE INNODB STATUSG,查看 LATEST DETECTED DEADLOCK 区域

日志里关键信息包括:

  • 每个事务持有的锁(HELD LOCKS
  • 正在等待的锁(WAITING FOR this LOCK TO BE GRANTED
  • 涉及的表名、索引名、具体记录的主键值(如 space id 123 page no 1024 n bits 72 后跟 record lock, heap no 5

真正难处理的是“锁等待链过长”而非死锁:比如事务 A 锁住行 X,事务 B 等 A;B 又锁住行 Y,事务 C 等 B……这种不会触发死锁检测,但会导致请求积,需靠 information_schema.INNODB_TRXINNODB_LOCK_WAITS 关联分析。

text=ZqhQzanResources