MySQL事务执行LOCK TABLE时是否只能同时持有一个表锁?
测试现象背后的核心原因
你观察到的结果和InnoDB引擎层的锁逻辑无关,根源是你使用的LOCK TABLES是MySQL Server层提供的表锁命令,它本身的两个默认行为直接导致了该现象:
- 执行
LOCK TABLES语句时,会隐式提交当前会话的所有活跃事务,同时自动释放该会话之前通过LOCK TABLES持有的所有表锁,无法累计持有多批LOCK TABLES申请的锁 - 只有单次
LOCK TABLES同时指定多个表时,才会一次性持有多个表锁,例如LOCK TABLES test1 WRITE, test2 WRITE可以同时持有两个表的写锁
锁状态按执行顺序拆解
完全匹配你给出的测试步骤:
- 会话1执行
begin开启事务后执行LOCK TABLE test1 write:首先隐式提交之前开启的空事务,释放会话1之前所有表锁(无),成功持有test1的写锁 - 会话2执行
begin开启事务后执行LOCK TABLE test2 write:同样隐式提交空事务,成功持有test2的写锁 - 会话1执行
LOCK TABLE test2 write:首先自动释放已经持有的test1写锁,再尝试申请test2的写锁,发现test2被会话2持有,进入阻塞 - 会话2执行
LOCK TABLE test1 write:首先自动释放已经持有的test2写锁,尝试申请test1的写锁,此时test1的锁已经被会话1释放,直接加锁成功;同时test2的锁已经被会话2释放,会话1的阻塞直接解除,成功持有test2的写锁
额外补充说明
如果要测试InnoDB事务层面的锁特性,不要使用Server层的LOCK TABLES命令,应该使用InnoDB引擎层面的锁语法,比如SELECT * FROM test1 FOR UPDATE,这类锁支持同一个事务持有多个不同的表/行锁,不会出现执行新加锁语句就释放旧锁的情况。
内容的提问来源于stack exchange,提问作者Angle Tom
相关产品推荐
相关产品推荐

