Mysql 事务版本链(RR 与 RC 的本质区别)

版本链其实就是CURD的历史记录,回滚的本质也是用版本链中的最近一条历史记录覆盖当前记录。版本链针对的是每个表中的记录,只要表中有任意一条记录被修改,版本链中就会新增一条历史记录。


         目录

1、为什么需要版本链?

2、有关版本链的前提知识

(1) ReadView

(2) 四个隐藏字段

(3) undo log(回滚日志)

2、单个事务的版本链

3、多个事务的版本链

4、RR 与 RC 的本质区别


扫描二维码关注公众号,回复: 14631773 查看本文章

1、为什么需要版本链?

一方面允许回滚。如果用户想撤销之前的操作,有了版本链就可以用之前的历史记录来覆盖当前历史记录,从而达到回溯的效果。

另一方面是控制事务的隔离性。先到来的事务无法看到后来的事务作出的修改,不同事务看到的可能是不同版本,修改的也是不同的版本,所以两个事务执行的操作并不会互相影响,这就达到了隔离两个事务的目的。

2、有关版本链的前提知识

(1) ReadView

每当有一个事务到来的时候,Mysql 就会创建一个ReadView(读快照),相当于相机拍下了那一时刻的事务状况,ReadView记录了在当前事务之前有哪些事务处在活跃状态,有哪些事务的历史记录允许被看到等等。

//一张列表,用来维护Read View生成时刻,系统正活跃的事务ID
m_ids; 

// 活跃事务中事务ID的最小值
up_limit_id; 

// 未来事务临界点(下一个事务到来时应该分配的ID,之后到来的事务都属于未来事务,历史记录不可被看到)
low_limit_id;      

// 创建该ReadView的事务ID(快照形成点)
creator_trx_id    

(2) 四个隐藏字段

每个表在被创建的时候,都会存在四个隐藏字段。我们对表中的每一条记录作出的任何操作,都会被保存下来(包括谁操作了该条记录、历史记录放在哪、该条记录是否被删除等)

  • DB_TRX_ID:最近修改 / 插入该条记录的ID
  • DB_ROLL_PTR:回滚指针,指向该条记录的上一个版本(一般在undo log)
  • DB_ROW_ID:隐含的自增ID。若数据表无主键, InnoDB 会自动以 DB_ROW_ID 产生一 个聚簇索引
  • flag:用于标识该记录是否被删除

(3) undo log(回滚日志)

其实就是保存日志数据,也就是历史记录。每次执行sql操作都会有历史记录产生,产生的结果将作为历史记录保存到undo日志文件中。针对不同的操作,隐藏字段的填充内容也会不同,产生的日志也会有些许不同:

  • update、delete:可以正常生成版本链
  • insert:因为没有历史记录,所以实际上会插入一条空的历史记录(此时回滚指针为NULL)
  • select:不会对数据作出修改,维护多个版本没有意义,不会生成版本链(历史记录)

2、单个事务的版本链

假设有一个10号事务到来,此时会形成一个“读快照”ReadView,记录下该事务到来时,有哪些事务是处于活跃状态、下一个事务到来时,应该分配的事务ID是多少等。

10号事务执行任何sql操作时都会产生历史记录,产生的历史记录保存到 undo log 中,每条记录中的隐藏字段 DB_ROLL_PTR 都会指向上一条历史记录。即便是历史记录也会指向自己的上一条记录。

3、多个事务的版本链

Mysql 中存在多个事务的时候,难免存在多个事务要修改同一行记录的情况,这个时候最好的办法就是加锁。就算有多个事务到来也必然存在先后顺序,此时Mysql会依次给他们创建快照(ReadView)。

假设有一个10号事务要修改记录,这个时候就会给该事务要修改的行加锁(我们称为“行锁”),修改之前将记录拷贝到undo log,这样就有了历史记录;修改完毕以后,释放 “ 行锁 ” 。

然后又有一个11号事务,也是要对同一行修改,首先也是加行锁,其次将之前的记录拷贝到undo log,最后再修改并提交。由此我们可以知道,每个事务可以看到的历史记录不一样,11号事务在10号事务之后,可以看到10号事务提交的记录;但是10号事务无法看到11号事务提交的记录。

4、RR 与 RC 的本质区别

从上述事务版本链可以大致了解到,事务是如何实现回滚、产生版本链以及保证彼此之间不会受到影响的。但是不同隔离级别下的事务,允许看到的版本链存在差异,比如读提交(RC)级别下,可以看到其他事务的提交结果;但是可重复读(RR)级别下,无法看到其他事务的执行结果直至当前事务提交。

  • RR级别:只有事务到来的时候,才会形成一次ReadView,之后就不再更新,此后使用的都是同一个ReadView,看到的其他事务的版本链也是固定的。
  • RC级别:每次快照读(查看历史版本)都会生成一个快照 和 ReadView,这就是每次查询出来的记录都是最新的原因。

猜你喜欢

转载自blog.csdn.net/challenglistic/article/details/129227583
今日推荐