行锁仅在InnoDB引擎、索引字段查询、UPDATE/DELETE/FOR UPDATE语句且事务未提交时生效;否则可能退化为表锁或间隙锁。表锁由MyISAM写操作、InnoDB无索引DML、DDL或显式LOCK TABLES触发。间隙锁在RR级别范围查询中启用,防止幻读。

SQL锁机制的核心在于“按需锁定、最小影响”。行锁和表锁不是随意触发的,而是由存储引擎、SQL类型、索引使用、事务隔离级别共同决定的。搞清触发条件,才能避免误锁、死锁和性能抖动。
行锁什么时候真正生效?
行锁(InnoDB默认)只在满足以下全部条件时才精确作用于单行:
- 使用InnoDB引擎——MyISAM不支持行锁,只支持表锁
- 操作语句涉及索引字段(主键、唯一索引或普通索引),且查询能走索引
- 执行的是UPDATE、DELETE或显式加锁的SELECT(如FOR UPDATE或LOCK IN SHARE MODE)
- 事务未提交,锁持续持有;若SQL执行后自动提交(autocommit=1),锁在语句结束即释放
⚠️ 注意:如果WHERE条件没走索引(比如用非索引列过滤、或LIKE '%abc'),InnoDB可能退化为全表扫描+逐行加锁,实际效果接近表锁,但开销更大。
表锁为什么突然出现?
表锁并非仅来自LOCK TABLES命令,它常在这些场景下被动触发:
- MyISAM引擎下的所有写操作(INSERT/UPDATE/DELETE)自动加表级写锁
- InnoDB中,对无索引字段执行UPDATE/DELETE,因无法定位具体行,引擎升级为表锁
- 执行DDL语句(如ALTER TABLE、DROP INDEX)时,MySQL会隐式加元数据锁(MDL),阻塞并发DML,表现类似强表锁
- 显式调用LOCK TABLES ... WRITE,适用于备份、迁移等短时批量操作
? 小技巧:用EXPLAIN检查执行计划,若type=ALL或key=NULL,大概率会引发非预期表级锁定。
间隙锁(Gap Lock)容易被忽略的触发点
间隙锁是InnoDB在可重复读(RR)隔离级别下防止幻读的关键机制,但它不是独立存在的锁类型,而是配合行锁使用的:
- 仅在RR级别启用(RC级别下默认关闭间隙锁)
- 出现在范围查询中:例如SELECT * FROM t WHERE id BETWEEN 5 AND 10 FOR UPDATE,不仅锁住已存在的5–10行,还会锁住(5,10)之间的空隙,阻止新记录插入
- 等值查询+唯一索引不会触发间隙锁(只加记录锁);但等值查询+非唯一索引会加间隙锁(如WHERE status='pending')
- INSERT操作本身不加间隙锁,但会检测是否与现有间隙锁冲突,冲突则等待
? 实战提醒:高并发插入场景下,若业务依赖非唯一索引做条件更新,间隙锁可能导致大量INSERT阻塞,应评估改用唯一约束或调整隔离级别。
怎么快速判断当前SQL加了什么锁?
不靠猜,靠查:
- 查当前锁等待:SELECT * FROM information_schema.INNODB_TRX;(看事务状态和运行时间)
- 查锁详情:SELECT * FROM information_schema.INNODB_LOCKS;(MySQL 5.7+ 已弃用,推荐用performance_schema.data_locks)
- 查锁等待关系:SELECT * FROM performance_schema.data_lock_waits;
- 查最近死锁日志:SHOW ENGINE INNODB STATUS\G;(重点关注LATEST DETECTED DEADLOCK部分)
锁分析不是一次性动作,而是结合慢查询日志、事务持续时间、QPS突降等指标交叉验证的过程。










