本篇主要以实际的操作来看一下MVCC在RC和RR这两个隔离级别下面的一个表现。
RC隔离级别
1、一致性视图生成时机
RC级别下面的一致性视图是在每次读取的时候都会生成一个。这里说一下,虽然读取生成一致性视图,但是其事务id也就是trx_id是在你第一次做增删改处理才赋予一个值的,普通查询就是0,前面说过了。
2、版本控制验证
1、开启两个事务,把隔离级别设置为RC
此时数据库里面只有一个初始数据。
根据上篇的描述我们在第一个事务里面做一些操作,以此来生成版本链。在第二个事务里面对别的表做更新操作,让他生成事务id。
此时做完了修改,我们来看看事务id。
OK,此时事务id都被分配,事务1的trx_id是2795535,事务2的trx_id是2795537。好像不是递增的,可能和生成规则那里有关,涉及表空间那里,这个此处不深究。
此时开启第三个事务,隔离级别依然是RC。
这个事务没有做操作,所以他的trx_id就是0。
我们来查询一下这个id=1的数据,然后看看mvcc的表现。注意此时事务1,2都还没有提交。
因为事务三只做了查询,此时他的事务号就是0,在此时他开启事务做查询那一刻生成一致性视图,此时这个一致性视图的属性值分别是:
1、m_ids:[2795535,2795537]
2、min_trx_id:2795535
3、max_trx_id:2795538
4、creator_trx_id:0
此时他开始从id=1的这个数据此时的版本链开始遍历,我再把版本链贴一下。
第一步:版本链上的最新数据是内马尔,其事务号是2795537,在m_ids当前活跃集合里面,说明你开启查询那一刻,内马尔这个数据是活跃的事务,还没提交呢。没提交的东西在RC下不能被看到,所以这个版本不可见。
第二步:继续顺着版本链往下走到苏牙这个版本,事务号是2795535,也在m_ids下面,所以不可见。
第三步:继续顺着版本链往下走到了梅西这个版本,看到了事务号是95,最开始插入时候的事务,此时他不在m_ids里面,并且小于min_trx_id,说明你开启事务查询的时候,这个事务的数据已经提交了,读已提交可以读到数据,所以结果就是梅西。
3、设计分析
这就是他的查询过程,我们分析一下设计。这里存在的设计就是他是每次读取都会生成一个视图,在RC隔离级别下,这种方式是保证了读已提交,他通过限制你读取的范围,保证了你读取到的都是不活跃的事务,也就是提交的事务,解决了RU下的读未提交的问题。
但是因为每次都会生成新的视图,可能在一个事务中读到两次数据,两次之间有的活跃的事务提交了,导致你读到的数据不一致,出现不可重复读。这就是RC规则的实现。
OK,具体其他场景就可以按着这个路子分析了,这里不多说了。