MySQL RR级别的实现

举报
JavaEdge 发表于 2022/02/16 22:59:19 2022/02/16
【摘要】 如何同时避免不可重复读问题和幻读问题的呢?MySQL让多个事务并发运行的时候能互相隔离,避免同时读写一条数据的时候有影响,是借助undo log版本链条和ReadView机制。RR级别下,你这事务读一条数据,无论读多少次,都是一个值:别的事务修改数据了后即使提交了,你也看不到人家修改的值,这就解决了不可重复读其它事务插入一些新数据,你也读不到,这就避免幻读假设有一条数据是事务id=50的一个...

如何同时避免不可重复读问题和幻读问题的呢?

MySQL让多个事务并发运行的时候能互相隔离,避免同时读写一条数据的时候有影响,是借助undo log版本链条和ReadView机制。

RR级别下,你这事务读一条数据,无论读多少次,都是一个值:

  • 别的事务修改数据了后即使提交了,你也看不到人家修改的值,这就解决了不可重复读
  • 其它事务插入一些新数据,你也读不到,这就避免幻读

假设有一条数据是事务id=50的一个事务插入的,此时有事务A、B同时在运行

这时,事务A发起了一个查询,第一次查询就会生成一个ReadView:

  • creator_trx_id=60
  • min_trx_id=60
  • max_trx_id=71
  • m_ids=[60, 70]

这时,事务A基于该ReadView去查这条数据,发现这条数据的trx_id为50,是小于ReadView

里的min_trx_id的,说明他发起查询之前,早就有事务插入这条数据还提交了,所以此时可以查到这条原始值的

接着事务B此时更新了这条数据的值为b,修改trx_id=70,同时生成一个undo log,事务B此时提交

ReadView中的m_ids此时还是60、70,因为ReadView一旦生成了就不会改变!

这时虽然事务B已提交,但事务A的ReadView里, 还是有60、70,即在你事务A开启查询时,事务B当时是在运行的意思而已。

然后事务A查询这条数据,发现此时数据的trx_id=70,在ReadView的min_trx_id和max_trx_id的范围,还在m_ids列表,这说明啥?

事务A开启查询时,id=70的这个事务B还在运行,然后由这个事务B更新了这条数据,所以此时事务A不能查询到事务B更新的这个值,因此顺着指针往历史版本链条上去找,找到trx_id=50,是小于ReadView的min_trx_id的,说明在他开启查询之前,就已提交该事务,所以事务A可查询到该值,此时事务A查到的就是原始值。这就解决了不可重复读。

事务A多次读同一个数据,每次读到的都是一样的值,除非是他自己修改的值,否则读到的一直一样。不管别的事务如何修改数据,事务A的ReadView始终不变,他基于这ReadView看到的值始终如一!

如何解决幻读

假设事务A先

select * from x where id>10

此时可能查到的就是一条数据,而且读到的是这条数据的原始值的那个版本:

现在,有个事务C插入一条数据,然后提交:

接着,事务A再查询,发现符合条件的有2条数据:

  • 原始值那个数据

  • 事务C插入的那条数据

    但C插入的那条数据的trx_id=80 > ReadView的max_trx_id,说明是自己发起查询后,这个事务才启动,所以此时这条数据不能查询。

因此事务A本次查询,还是只能查到原始值那一条数据。所以这里事务A不会发生幻读,他根据条件范围查询的时候,每次读到的数据都是一样的,不会读到人家插入进去的数据,这都是依托ReadView机制实现的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。