InnoDB行锁仅在SQL走索引、开启事务且隔离级别合理时生效;否则退化为全表锁,并发性能接近甚至低于MyISAM。

InnoDB行锁在高并发读写中并不天然优于MyISAM表锁——它只在满足特定条件时才真正生效;否则,UPDATE或SELECT ... FOR UPDATE会退化为全表锁,实际表现甚至比MyISAM更差。
行锁只在走索引时才真正加在“行”上
InnoDB的“行锁”本质是加在索引记录上的,不是物理行。一旦WHERE条件没命中索引,引擎就会全表扫描并逐行尝试加锁,效果等同于锁表。
-
WHERE id = 100(主键等值)→ 只锁单行(Record Lock) -
WHERE status = 1(普通索引+范围)→ 锁匹配索引项及间隙(Next-Key Lock) -
WHERE remark LIKE '%test%'(无索引字段)→ 全表扫描 → 每行都加锁 → 实际并发能力≈MyISAM -
WHERE DATE(create_time) = '2026-10-14'→ 函数导致索引失效 → 同样退化
MyISAM表锁是硬性写优先,不看WHERE条件
MyISAM对任何UPDATE/DELETE/INSERT都直接申请整张表的WRITE LOCK,不管你要改的是哪一行、是否加了索引、WHERE多精准——锁就是整张表。
- 两个事务分别更新
id = 1和id = 100000→ 仍互相阻塞 - 一个慢
SELECT正在执行 → 所有写操作排队等待 -
concurrent_insert = 1仅允许尾部INSERT并发,UPDATE/DELETE照旧锁表 - 没有事务支持,崩溃后无法回滚,只能靠
REPAIR TABLE人工救火
InnoDB行锁的代价常被低估
行级锁不是零成本开关。它带来真实开销:内存占用高、加锁路径长、死锁风险明确存在。
- 每个锁对象需维护在内存中,可通过
INFORMATION_SCHEMA.INNODB_TRX查活跃事务 -
innodb_lock_wait_timeout默认50秒,线上建议调成5~10秒,避免掩盖锁争用问题 - 热点行(如频繁更新
status字段)易引发Lock wait timeout exceeded - 批量更新务必显式用
BEGIN+COMMIT包裹,单事务控制在≤5000行,防undo log暴涨
别只看ENGINE=InnoDB就以为自动高并发
真正决定并发表现的是SQL执行时触发的实际锁行为,而不是建表语句里写的引擎名。
- 用
EXPLAIN确认type是const或ref,不是ALL(全表扫描) - 避免在索引列上做隐式类型转换(如
WHERE user_id = '123'而user_id是INT) - 检查
SHOW ENGINE INNODB STATUS里的LATEST DETECTED DEADLOCK段,定位死锁源头 - SSD环境下,InnoDB的离散小写更适配硬件并行通道;MyISAM串行化写入反而浪费低延迟优势
最常被忽略的一点:行锁是否生效,完全取决于你写的那条SQL有没有真正走到索引上——而这一点,EXPLAIN说了算,不是DBA说了算,也不是引擎文档说了算。











