MySQL 5.6 InnoDB可重复读级别下select for update阻塞问题及疑问
解答MySQL InnoDB中
select ... for update阻塞的疑问 这个问题其实是把表级意向锁和行级锁的作用搞混了,我来一步步拆解清楚:
首先直接说核心原因:你提到的IX锁兼容是表级锁的规则,但select ... for update真正导致阻塞的是行级X锁的排他性。T1先执行语句后,已经给id=1的行加了行级X锁,T2再执行相同语句时,虽然表级IX锁可以共存,但请求同一行的X锁时会被T1持有的行X锁阻塞,这就是关键。
接下来逐个解答你的疑问:
疑问1:select for update是否先给表加IX锁,再给匹配的索引/行加X锁?
- 没错,这个执行流程是完全正确的。InnoDB在处理
select ... for update时,首先会给目标表添加表级IX锁(意向排他锁,作用是给其他事务打个招呼:我接下来要给表中的某些行加排他锁了),然后根据查询条件定位到匹配的行——如果有可用的索引(比如你这里的id是主键索引),就会通过索引精准定位到目标行,给这些行(或者对应的索引记录)添加行级X锁;如果没有合适的索引,就会升级为表级X锁,那整个表都会被锁住。
疑问2:X锁和S锁可以是表级或行级锁吗?
- 当然可以,这两种锁都有表级和行级的实现:
- 表级的X/S锁:比如执行
LOCK TABLES t WRITE;会给表加表级X锁,此时其他事务完全无法对这个表做写操作,读操作也会被阻塞;LOCK TABLES t READ;会加表级S锁,其他事务可以读但不能写。 - 行级的X/S锁:就是针对具体行的细粒度锁,比如
select ... for update会给匹配行加行级X锁,select ... lock in share mode会加行级S锁,这种锁只会影响被锁定的行,表中其他行的操作不受影响。
- 表级的X/S锁:比如执行
疑问3:官方文档锁兼容矩阵中的X、S指的是表级锁而非行级锁吗?
- 对的,官方文档里和IX、IS一起出现在兼容矩阵里的X、S都是表级锁。因为意向锁(IX/IS)本身就是表级锁,它们的核心作用是协调表级锁和行级锁之间的冲突——比如当一个事务持有表级IX锁时,另一个事务请求表级X锁会被阻塞,因为IX锁表明当前表中已经存在行级X锁,不能直接加表级X锁。而行级锁的兼容规则是独立的:行级X锁和任何行级锁(X/S)都冲突,行级S锁和行级S锁兼容,和行级X锁冲突。
疑问4:T2被阻塞是否因为表级IX锁兼容,但行级X锁冲突导致?
- 完全正确!这就是问题的本质。表级的IX锁之间是互相兼容的,所以T2可以正常获取表级IX锁,但当它要给
id=1的行加行级X锁时,发现T1已经持有该行的行级X锁,而行级X锁是排他的,所以T2必须等待T1释放该行的X锁才能继续执行,这就出现了你看到的阻塞现象。
内容的提问来源于stack exchange,提问作者frank
相关产品推荐
相关产品推荐

