文章目录

  • 当前读与快照读
  • 两个场景
  • RR 与 RC的本质区别



本篇博客介绍的是RR与RC的本质区别,话不读说,直接进入主题即可。

当前读与快照读

select * from user lock in share mode ,以加共享锁方式进行读取,对应的就是当前读

不加lock in share mode就是快照读

  • 设置隔离级别RR

首先设置隔离级别RR

set global transaction isolation level repeatable read;

设置完毕之后要进行重启终端才会生效。

mysql rr rc 原理_数学建模

两个场景

现在创建一张表插入一条数据用于测试:

insert into user (id, age, name) values (1, 15,'黄蓉');

mysql rr rc 原理_mysql_02

情景一:事务A和事务B开启事务,然后对事务A与事务B进行快照读是一样的结果,现在对事务A更新数据age=18,然后提交事务;此时事务A已经是提交的了;而事务B进行快照读select * from,没有读取到18,这很好理解,这是可重复读的隔离级别嘛,事务B提交之后才能看到;但是如果此时事务B没提交,而事务B此时进行当前读select lock in share mode则可以读取到18

mysql rr rc 原理_隔离级别_03

启动两个终端分别对应事务A与事务B,结果如下图所示:

mysql rr rc 原理_mysql rr rc 原理_04

在隔离性这里如果想读到最新数据也是可以读到的。

情景二:事务A的操作与情景一是一样的,事务A把age改成了28;但是事务B进行快照读是在事务A提交之后才进行的,此时看到的是28,之后如果在进行当前读读取到的也是28

mysql rr rc 原理_数据库_05

情景一与情景二:唯一区别仅仅是表1的事务B在事务A修改age前快照读过一次age数据;而表2的事务B在事务A修改age前没有进行过快照读

对于情景一:事务B在快照读的时候mysql就给事务B形成了一个read view;快照的对象认为A是与其一块运行的。事务B认为事务A在自己的m_ids列表中。所以看不到事务A提交的修改了。情景二:事务B并没有快照读,没有形成read view对象,事务A提交之后才进行快照读,此时看待并发的事务时,事务A已经不存在了,此时事务B看到的事务列表的最小值都比事务A大,事务B 能看到事务A的修改。

事务中快照读的结果是非常依赖该事务首次出现快照读的地方,即某个事务中首次出现快照读,决定该事务后续快照读结果的能力;delete同样如此

RR 与 RC的本质区别

正是Read View生成时机的不同,从而造成RC,RR级别下快照读的结果的不同;在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来
此后在调用快照读的时候,还是使用的是同一个Read View,所以只要当前事务在其他事务提交更新之前使用过快照读那么之后的快照读使用的都是同一个Read View,所以对之后的修改不可见。

即RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的而早于Read View创建的事务所做的修改均是可见
而在RC级别下的事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因

总之在RC隔离级别下,是每个快照读都会生成并获取最新的Read View;而在RR隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快照读获取的都是同一个Read View。正是RC每次快照读,都会形成Read View,所以,RC才会有不可重复读问题。