MySQL为什么select在update之后就不是快照读了?

在了解MySQL中事务隔离级别的时候,学到这个例子:

1972856099-64142aacc641f_fix732.png

为什么事务A第二次select就能查到了,按照mvvc机制来说,不应该还是查不到吗?即使id=5的这一条数据是事务id是A,但是它还是介于m_up_limit_id(事务A的id)和m_low_limit_id(事务B的id加1)之间,所以还是查不到啊,为什么说第二次select就可以查到id=5的这条记录了?

阅读 4k
3 个回答

image.png

原文链接

破案了,原来匹配规则还有一条,我看了很多讲mvvc的博客,都漏掉了第一条。我题目中说的情况满足第一条匹配规则,所以能读取到。

首先你没有说是什么隔离界别,既然提到了MVCC 那就认为是RR可重复读。

  • 事务A开启事务后,普通select查询,为快照读。
  • 在事务B执行时,并没有产生任何数据锁定,所以事务B正常执行并提交。
  • 事务A执行update,此时为当前读。他可以读取到最新的数据,即有id=5的数据存在。由于id为主键且数据存在,只有record lock。
  • 然后查询id=5的记录,就是自己刚刚更新的 小林

如果事务A在最开始使用select .. for update,那么由于id=5的数据不存在,会加gap lock,这样就会导致后续的事务B执行insert时阻塞,直到A事务提交完成后,才会继续执行(假如没超时或其他中断的情况下)。


本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。

你所说的正是mysql默认隔离级别产生幻读现象之一。

事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 5 的记录并提交。接着,事务 A 对 id = 5 这条记录进行了更新操作,在这个时刻,这条新记录的 trx_id 隐藏列的值就变成了事务 A 的事务 id,之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了,于是就发生了幻读。

这个问题的重点在于快照读,快照读可以获取所有 行事务id<=当前事务的id 的行记录,而并不是和它的名字一样产出了所谓的临时表(快照),其他事务改不了。

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏