MySQL 锁怎么理解:表锁、行锁、意向锁和索引边界

1次阅读
没有评论

MySQL 锁问题最容易让人困惑:明明只更新一行,为什么阻塞了一大片?明明用了 InnoDB,为什么像表锁?关键在于存储引擎、锁粒度和索引条件。

锁粒度决定并发能力

表级锁锁整张表,开销低,冲突范围大。行级锁锁具体行,开销更高,但并发能力更好。页级锁介于两者之间。

MyISAM 主要使用表锁,适合读多写少、并发写入要求不高的老场景。InnoDB 支持事务和行级锁,适合在线事务处理系统。

只看锁粒度还不够。锁模式也分读锁和写锁。读读兼容,读写冲突,写写冲突,这是理解阻塞关系的基本表。

MyISAM 的读写是表级串行

MyISAM 表读操作会阻塞写操作,但不阻塞其他读;写操作会阻塞读和写。一个线程拿到写锁后,其他线程只能等锁释放。

MyISAM 有一些读写优先级和并发插入参数可以调,但这些只能缓解特定场景。现代业务如果需要事务、崩溃恢复和高并发写入,通常不该再把 MyISAM 作为默认选择。

InnoDB 行锁依赖索引

InnoDB 的行锁是加在索引记录上的。只有通过索引条件检索数据,才更可能锁住目标行;如果条件没有走索引,InnoDB 可能扫描并锁住更多记录,表现得像表锁。

例如:

select * from orders where id = 1 for update;

如果 id 是索引,锁范围清晰。如果查询条件没有索引,数据库无法快速定位记录,就可能扩大锁范围。

这也是为什么更新和删除语句必须特别关注 where 条件是否命中索引。

意向锁解决表锁和行锁冲突

一个事务锁住了某些行,另一个事务想给整张表加写锁,数据库怎么快速判断是否冲突?如果逐行扫描,成本太高。

意向锁就是为了解决这个问题。事务在给行加共享锁或排他锁前,先在表上加意向共享锁或意向排他锁。后来申请表锁的事务只要看表级意向锁,就知道表内可能已有行锁冲突。

意向锁是 InnoDB 自动加的,业务代码通常不需要手动申请。

显式加锁要知道语义

普通 SELECT 在 InnoDB 下通常不加锁,依靠 MVCC 读取快照。

如果需要锁定读取,可以使用:

select * from table_name where id = 1 lock in share mode;
select * from table_name where id = 1 for update;

共享锁适合确认记录存在并防止别人修改;排他锁适合后续要更新当前记录的场景。

显式锁要尽量缩短事务时间。拿锁后做远程调用、复杂计算或等待用户输入,都会把数据库并发拖垮。

实用结论

MySQL 锁排查先问四件事:用的什么引擎,锁粒度是什么,SQL 是否走索引,事务持锁时间多长。

InnoDB 不等于永远只锁一行。没有合适索引、范围条件过宽、事务太长,都可能让锁冲突扩大。锁问题的根治通常不是“调一个参数”,而是改 SQL 条件、补索引、缩短事务和明确并发边界。

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-07-05发表,共计1122字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)