MYSQL隔离性原理——MVCC

表的隐藏字段

表的列包含用户自定义的列和由系统自动创建的隐藏字段。我们介绍3个隐藏字段,不理解也没有关系,理解后面的undo log就懂了:

  • DB_TRX_ID :6 byte,最近修改( 修改/插入 )事务ID,记录创建这条记录/最后一次修改该记录的事务ID
  • DB_ROLL_PTR : 7 byte,回滚指针,指向这条记录的上一个版本(简单理解成,指向历史版本就行,这些数据一般在 undo log 中)
  • DB_ROW_ID : 6 byte,隐含的自增ID(隐藏主键),如果数据表没有主键, InnoDB 会自动以DB_ROW_ID 产生一个聚簇索引

undo log

undo log是一个缓冲区,用来存放记录修改的历史记录。

以下面这个表为例讲解:

当我们插入一条记录后,这个表中的内容实际上是这样的:

|----|------|------------------|-------------|-----|
| id | name | DB_TRX_ID | DB_ROLL_PTR | ... |
| 1 | Tom | 创建当前记录的事务id,假设为1 | null |

如果我们在一个事务中修改这个记录,它的过程是这样的:

先将当前记录做备份,放到undo log中。同时将修改后的记录的DB_ROLL_PTR设置为上一个记录的地址。就这样将记录的每个版本都用回滚指针连起来,形成一个版本控制链 。当我们想要回滚到某个版本时,就可以直接找到。这一个个版本,我们称之为快照。

另外,不需要考虑undo log满的情况。在一个事务commit之后,修改记录的所有版本都会释放。

ReadView

undo log看起来和隔离性没什么关系,其实不然。隔离性是由undo log和readview配合实现的!

先介绍连个两个概念:

当前读:读取最新的记录,就是当前读。增删改,都叫做当前读。

快照读:读取记录的历史版本(一般而言),就叫做快照读。


Readview是一个类,可以记录数据库当前活跃事务的id,以及事务id的分配情况,相当于当前数据库的一个快照。我们简单了解几个类成员:

  • m_ids; //一张列表,用来记录Read View生成时,系统正进行的事务的ID
  • up_limit_id; //记录m_ids列表中事务ID最小的ID,小于这个值的事务id,就说明这个事务已经commit了。
  • low_limit_id; //ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1。大于这个id值的事务,就是在Read View生成后新开始的事务。
  • creator_trx_id //创建该ReadView的事务ID

隔离性的实现

ReadView会在事务进行快照读的时候创建,此时,事务会被分成三类:

对于read uncommitted,这三类事务的记录快照对于当前进行的事务来讲全部可见。

对于read committed和repeatable read,在第一个区间的事务id的记录快照可见;在第二个区间内但是不在m_ids中的事务的记录快照也可见,但是在m_ids中的事务的记录快照不可见;在第三个区间的事务的记录快照不可见。

那么,RC和RR的区别在哪?

对于RC,当前事务每次进行快照读的时候,都会创建ReadView。因此,当并行事务commit后,再进行快照读,这条记录就会变得可见。

对于RR,只在事务第一次进行快照读时创建ReadView,后续不会再创建。因此,不管并行的事务是否commit,都无法看到修改后的记录。

相关推荐
且行志悠14 分钟前
Mysql的使用
mysql
白鹭15 分钟前
MySQL源码部署(rhel7)
数据库·mysql
666和77742 分钟前
Struts2 工作总结
java·数据库
还听珊瑚海吗1 小时前
SpringMVC(一)
数据库
星期天要睡觉2 小时前
MySQL 综合练习
数据库·mysql
Y4090012 小时前
数据库基础知识——聚合函数、分组查询
android·数据库
JosieBook3 小时前
【数据库】MySQL 数据库创建存储过程及使用场景详解
数据库·mysql
处女座_三月3 小时前
改 TDengine 数据库的时间写入限制
数据库·sql·mysql