背景

mvcc是一种同悲观锁和乐观锁的一种并发锁模式,用以解决mysql并发访问同一行数据因阻塞而过慢的问题。

mvcc

MVCC
MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

mysql在rr和rc隔离模式下,事务快照读访问一行数据,会生成一个readview,并在undo log日志里生成一条记录,且你快照读访问的那条记录的隐式字段也会修改

记录的隐式字段

db_trx_id:记录着上一个要对次修改的事务

db_row_id:记录该记录的隐藏主键

db_roll_ptr:记录着该记录要回滚的上一个版本的指针

undo log

undo log分为两种

insert undo log

update undo log

cdh对于Mysql的配置 mysql cdc模式_数据库

cdh对于Mysql的配置 mysql cdc模式_mysql_02

 

参考:mysql技术内幕 Innodb存储引擎第二版

如上图所示update undo log在insert undo log中做了一些补充,*代表对此字段进行了压缩

所以我先说insert undo log的字段

next记录着下一个undo log的位置,start记录着undo log的开始位置

type_cmpl记录此undo log的类型

undo_no记录着事务id(mvcc要素

table_id记录着表id

剩余的n_unique_index指这行记录唯一键值

update undo log与insert undo log相同字段名的字段意义大都相同,

除了type_cmpl

trx_undo_del_mark_rec:标记删除操作

trx_undo_upd_del_rec:更新一个已被删除的记录

trx_undo_upd_exist_rec:普通更新

data_poll_ptr(回滚指针)记录上一个undo log记录位置(mvcc要素,用作回滚操作),其他的如下图,很多都方便不理解,估摸着要有机会在深入

cdh对于Mysql的配置 mysql cdc模式_mysql_03

  参考:MySQL · 引擎特性 · InnoDB undo log_bohu83的博客-CSDN博客

 readview

在一个事务开启后,并在一段时间后访问一条数据,会对该行数据执行快照读,生成针对与该行数据和该事务的一个readview,这是mvcc最后的一个实现要素

readview简单理解有三个属性:

一个是存放快照读执行时或者readview生成前一刻,当前这段数据所有的活跃事务的id列表,我们暂且称这个列表的名字是trx_list

一个是trx_list中最小的trx_id,up_limit_id

一个是快照读执行时或者readview生成前一刻,下一个尚未分配的事务id,low_limit_id

整体流程

mvcc主要原理就是将undo链表记录中的事务id与readview中的三个属性进行比较,判断事务可以看到哪一个版本的数据

参考:【MySQL笔记】正确的理解MySQL的MVCC及实现原理_SnailMann的博客-CSDN博客

事务1开始执行,修改完行数据并提交,并更改行数据的隐式字段trx_id

事务2开始执行,修改行数据,并在undo log里生成undo记录,记录事务2要修改的信息

事务3开始进行快照读,发现undo log存在这条行记录的最近修改,生成readview记录所有当前事务id(2),并取得最近提交的事务id,赋给up_limit_id,将下一个生成事务的id赋给low_limit_id,

事务4开始执行,修改完数据并提交

当事务3再次查询时,会把之前生成的readview与undo log里的记录作比较,判断可见性,

如果这一行undo记录的事务id>low_limit_id,代表着这一行的事务在readview生成时还未执行,这肯定就是不可见的,进行下一次判断,反之则再次判断id是否大于up_limit_id,如果小于,则直接判断的此条记录可见并返回,反之则判断trx_list是否包含此id,如果包含,代表这个事务在readview生成的时候还没有开始执行,所以是不可见的,反之则代表,readview生成的时候,它已经提交了,所以是可见的

关于判断可见性这一块,我整理了下   up_limit_id, low_limit_id, trx_list

1,大于lowid,则代表,在readview生成之前

2,小于lowid,大于upid,代表在readview生成后,分为两个可能

        1,已经结束,是可见的,则它在trxlist中

        2,未结束,是不可见的,则它就不再trx_list中

3,小于upid,代表此事务在readview生成前就已经提交了

4,例外,在事务重新对行数据进行当前读之后,会重新更新readview

个人瞎想

我感觉的有些拗口,,似乎是readview生成时行记录记录的trx_id,trx_id是行记录最近提交事务的id,但我觉得似乎没有用到,然后我再想了下,似乎是我们只有通过最新行数据的roll_ptr(回滚指针)来定位数据

其次,一开始我想不通的一个点,我猜更改事务是基于最新提交的数据在undolog生成记录的,而不是在undolog里的最新的不知道到提没提交,或者已经回滚的数据的基础上生成undolog记录的(这是我想不通的点),所以每次快照读事务读到的必是一个可见的,且不是其他事务不知道提没提交,或者回没回滚得的数据