写点什么

MySQL RR 级别的实现

作者:JavaEdge
  • 2022 年 2 月 16 日
  • 本文字数:1051 字

    阅读完需:约 3 分钟

MySQL RR级别的实现

RR 级别的实现

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


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 机制实现的。

发布于: 刚刚阅读数: 2
用户头像

JavaEdge

关注

正在征服世界的 Javaer。 2019.09.25 加入

曾就职于百度、携程、华为等大厂,阿里云开发者社区专家博主、腾讯云+社区2019、2020年度最佳作者、慕课网认证作者、CSDN博客专家,简书优秀创作者兼《程序员》专题管理员,牛客网著有《Java源码面试解析指南》。

评论

发布
暂无评论
MySQL RR级别的实现