事务(四)
MVCC实现
1)Mutli-Version Concurreny Control,
快照读:
当前读:
ibd文件(
回滚段中存储
2)数据行结构
多版本并发控制,读不加锁,读写不冲突。
应用于 Read Commited 和 Repeatable read 两个事务隔离级别。快照读:
普通的select,不加锁,读取记录的可见版本。
当前读:
select...lock in share mode/for update、update、insert、delete,读取记录最新版本,并加锁。
ibd文件(
又叫表空间
)中包含数据段,索引段,回滚段(undo log)
回滚段中存储
undo log
,所谓的多版本数据
指的是undo log中的多条记
2)数据行结构
DB_TRX_ID: 这行数据最后插入或修改的事务id
DB_ROLL_PTR:
DB_ROW_ID:
当该行数据被更新的时候,修改前的内容记录到undo log中,回滚指针指向该条undo log记录
DB_ROW_ID:
表中不存主键 或者 唯一索引,那么数据库 就会采用DB_ROW_ID生成聚簇索引。
3)undo log
作用:
存储位置:
创建时间:
作用:
undo log是为回滚而用,具体内容就是copy事务前的数据库内容(行)到undo buffer,在适合的时间把undo buffer中的内容刷新到磁盘。
存储位置:
所有的undo log均存放在主ibd数据文件(表空间)中
创建时间:
每次对数据进行更新操作时,copy 当前数据,保存到undo log 中,并将当前行的回滚指针指向undo log中的旧记录
4)Read View(一致性视图)判断行的可见性
read view (主要用来判断当前版本数据的可见性。):
read view (主要用来判断当前版本数据的可见性。):
创建一个新事务时,copy一份当前系统中的活跃事务列表。意思是,当前不应该被本事务看到的其他事务id列表。
注意:read view列表(区间范围T_min~T_max)定义:T_min为=当前活跃事务(活跃:已开启但未提交的所有事务)中事务id的最小值,T_max=事务自增id当前值+1(即当前事务id)。
在每次语句执行的过程中,都关闭read_view, 重新创建当前的一份新的read_view。如下:
read view中事务区间
...执行sql,创建一份最新的read_view;
...
...
...
Repeatable read各级离别下判断算法:T_min~T_max(T2)
,当前快照数据隐藏行DB_TRX_ID为:T1,当前事务id为:T2(即区间T_max),判断流程如下:...执行sql,创建一份最新的read_view;
...
T1<T_min
,说明T1事务比较早,该行对当前事务T1可见。...
T1 > T_max
,说明T1比较晚,该行对当前事务不可见,根据DB_ROLL_PTR
找到上一个判断再次判断。...
T_min <= T1 <= T_max
,如果read_view中有该行数据事务id(T1),则不可见,根据DB_ROLL_PTR
找上一个版本。如果不在,代表T1数据行是之前已提交(非活跃)的事务数据行版本则可见。创建事务trx结构的时候,就生成了当前的global read view。
注意:
Repeatable read与Read Commited两种隔离级别的判断逻辑是一样的,区别在于read_view的创建时期不一样,read committed (每次执行sql之前都重新创建)总是读最新一份快照数据,而repeatable read (事务就创建)始终读事务开始时创建的快照数据。所以Read Commited事务级别前后执行sql读取快照数据不一致就会导致不可重复读的问题,而Repeatable read在当前事务内读取的都是同一份快照数据,可以避免不可重复读的问题
实例
1)初始行
2)事务1更新操作(因为update会加排他锁X,所以undo log都是排队顺序的,不会出现两个事务并发增加undo log)
3)事务2更新操作
转载:https://www.jianshu.com/p/adb15359d924
带着疑问去思考,然后串联,进而归纳总结,不断追问自己,进行自我辩证,像侦查嫌疑案件一样看待技术问题,漆黑的街道,你我一起寻找线索,你就是技术界大侦探福尔摩斯