表锁快但并发差,因其直接锁整张表,无需查索引、开销小,但同一表的所有操作必须串行;innodb 行锁需 where 命中索引才生效,否则退化为表锁。

表锁为什么快但并发差?关键看加锁粒度
表锁直接锁整张表,MySQL 不用查索引、不定位行,所以 加锁快、开销小 。MyISAM 默认就用它, 不会死锁——因为锁的只有“表”这个单一资源,事务间不存在交叉等待链。但代价也很直接:哪怕两个 UPDATE 改的是完全不同的行,只要操作同一张表,就得排队。
- 读锁(
LOCK TABLES t READ):其他事务还能读,但所有写操作(INSERT/UPDATE/DELETE)全部阻塞 - 写锁(
LOCK TABLES t WRITE):其他事务连 SELECT 都不让,彻底串行化 - 典型陷阱:在 InnoDB 里执行
UPDATE没走索引(比如WHERE name = 'xxx'但name无索引),InnoDB 会自动退化为表锁——你以为是行锁,实际已拖垮并发
行锁真能并发高?前提是 SQL 必须走索引
InnoDB 的行锁本质是“锁索引项”,不是锁物理行。这意味着:只有 WHERE 条件命中索引(主键、唯一索引、普通索引均可),才能真正锁住几行;否则就是全表扫描 + 表级锁。
- 正确示例:
UPDATE user SET balance = 100 WHERE id = 123(id是主键)→ 锁单行 - 危险示例:
UPDATE user SET balance = 100 WHERE status = 'pending'(status无索引)→ 锁整张表 - 注意间隙锁:
WHERE id > 10 AND id 这类范围查询,InnoDB 还会锁住 (10,20) 之间的“间隙”,防止幻读——这属于行锁的延伸行为,不是额外加锁,但会影响并发插入
怎么判断当前是不是被表锁卡住了?看这两个状态值
当应用突然变慢、UPDATE/INSERT 大量超时,先别急着查慢 SQL,先确认是否陷入表锁争抢:
SHOW STATUS LIKE 'table_locks%';
-
table_locks_immediate:立刻获得表锁的次数(健康值应远高于另一项) -
table_locks_waited:因表锁等待的次数;如果该值持续增长,说明存在严重表级锁竞争 - 补充检查:
SHOW OPEN TABLES WHERE In_use > 0;可看到哪些表正被显式锁定(FLUSH TABLES WITH READ LOCK或LOCK TABLES导致)
InnoDB 里什么时候该主动用表锁?别迷信“行锁一定更好”
行锁不是银弹。在某些场景下,表锁反而更稳、更可控:
- 批量导入数据前:
LOCK TABLES t WRITE,避免其他事务干扰,比逐行加 X 锁开销低得多 - 维护性操作(如
OPTIMIZE TABLE、ALTER TABLE加索引):这些 DDL 本身就会触发 MDL 写锁,再叠加行锁只会增加死锁概率 - 小表高频更新:比如配置表
sys_config只有 10 行,InnoDB 行锁管理成本可能反超表锁——此时SELECT …… FOR UPDATE不如直接LOCK TABLES干净
最常被忽略的一点:锁的选择从来不是“引擎决定”的,而是由 SQL 写法、索引设计、事务隔离级别共同决定的。一个没走索引的SELECT …… FOR UPDATE,在 InnoDB 里照样变成表锁——代码没写错,但效果和 MyISAM 一样。






























