MVCC机制

个人理解篇,不一定对,应付面试的时候看的

MVCC(Multi-Version Concurrency Control)全称多版本并发控制,主要用在隔离模式下的提交读、可重复读模式下,依赖于readview和undolog链

一、readview

1、结构

|----------------|--------------------|
| 字段 | 备注 |
| m_ids | 活跃事务id集合 |
| min_trx_id | 活跃事务id集合中最小事务id |
| max_trx_id | 当前分配给新事务的最大事务id+1 |
| creator_trx_id | 生成readview时,当前事务id |

2、举例

现在系统中开启了事务A、B、C,对应的trx_id分别是1、2、3

此时有个新事务的读操作时,会产生如下readview

|----------------|-------|
| m_ids | 1,2,3 |
| min_trx_id | 1 |
| max_trx_id | 5 |
| creator_trx_id | 4 |

二、undolog链

1、结构

|-------------|---------------------------------|
| 字段 | 备注 |
| trx_id | 事务id |
| roll_point | 上一事务指针,指向上一个undolog节点 |
| key | 操作行记录的主键id |
| type | 执行类型(update、insert、delete) |
| commonvalue | 具体的值,没搞清楚具体是什么,但是新值、旧值、更新逻辑应该都有 |

2、举例

现在系统中开启了事务A、B、C,对应的trx_id分别是1、2、3

此时有个新事务的读操作时,会读取一下undolog链如下

三、操作

1、新事物发起读操作时产生readview,然后从undolog链开始查找并进行如下判断逻辑

if(trx_id == creator_trx_id)访问的是自己的事务,允许访问

if(trx_id < min_trx_id)访问的是已经提交的事务,允许访问

if(trx_id >= max_trx_id)访问的是在生成readview之后的事务,不允许访问

if(min_trx_id <= trx_id < max_trx_id)访问的是活跃中未提交的事务,不允许访问

ps:

1、关于undo链中的举例结构图,其实可以看出,默认在 trx_id=1的条目之前还会有trx_id=0的条目 这个条目是在生成readview时最新的提交数据,在trx_id=3后如果有新事务的话,其实也还有指向trx_id=3的事务,这只是个片段,具体的判断阶段会在这图中这一部分判断的比较集中。

2、关于trx_id=1指向的上一个已提交事务的undolog条目,由mysql来采取一些算法来判断是否存在,一般在被引用的时候都是存在的,不必担心找不到已提交的undolog条目

3、每个undolog条目都是某个表的某一行的数据,如果update修改了10条记录,那么会产生10个undolog条目,同时每个undolog链其实只是某一行的版本变化

四、关于

1、RC和RR区别

mvcc可以在RC(读已提交)和RR(可重复读)中,区别就是RC模式下,每次读都会产生readview,而在可重复读模式下,事务结束之前都是复用事务开始后的第一次读产生的readview

2、RR幻读问题

RR中其实没有完全解决幻读问题,如下场景

2.1表Subject:
场景一:

|-----------------------------------------------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| 事务A | 事务B | 事务B查询结果 |
| start TRANSACTION; | start TRANSACTION; | |
| | select * from Subject where difficultly = "困难"; | |
| insert into `Subject`(difficultly,type,language) value ('困难','英语','C'); commit; | | |
| | select * from Subject where difficultly = "困难" for update; | |
| | select * from Subject where difficultly = "困难" | |

可以看到第四步的当前读会出现幻读,而第五步的快照读仍然正常

场景二:

|-----------------------------------------------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| 事务A | 事务B | 事务B查询结果 |
| start TRANSACTION; | start TRANSACTION; | |
| | select * from Subject where difficultly = "困难" for update; | |
| insert into `Subject`(difficultly,type,language) value ('困难','英语','C'); commit; | | |
| | select * from Subject where difficultly = "困难" for update; | |
| | select * from Subject where difficultly = "困难" | |

第三步中事务A在执行插入时会一直无法执行完成,直到事务B中commit后才会执行完成

场景一和场景二区别:

场景一中事务B在事务A插入新数据和提交后执行的当前读,而场景二中事务B在事务A插入新数据和提交前执行的当前读,mysql通过mvcc和临键锁会锁定当前读,这样事务A再插入就插入不了新数据了,就解决了幻读,而场景一是在使用临键锁之前提交的,当前读读的是最新数据,所以会出现幻读

相关推荐
踏过山河,踏过海1 小时前
Django自带的加密算法
数据库·django·sqlite
黑白极客2 小时前
如何判断一个数据库是不是出问题了?
数据库·mysql
不辉放弃2 小时前
Spark的累加器(Accumulator)
大数据·数据库·spark
aini_lovee3 小时前
python命令行解析模块argparse
服务器·前端·数据库
Chase_______3 小时前
redis快速入门及使用
java·数据库·redis·学习·spring·缓存
不辉放弃3 小时前
Spark的宽窄依赖
大数据·数据库·pyspark
noravinsc3 小时前
django 按照外键排序
数据库·django·sqlite
ALLSectorSorft3 小时前
相亲小程序聊天与互动系统模块搭建
java·数据库·sql·microsoft·oracle
鼠鼠我捏,要死了捏4 小时前
MySQL 索引设计与查询性能优化实践指南
数据库·mysql·性能优化