MySQL 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机制实现的。
- 点赞
- 收藏
- 关注作者
评论(0)