表锁快但并发差,因其直接锁整张表,无需查索引、开销小,但同一表的所有操作必须串行;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一样。











