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再插入就插入不了新数据了,就解决了幻读,而场景一是在使用临键锁之前提交的,当前读读的是最新数据,所以会出现幻读

相关推荐
tiancaijiben20 小时前
阿里云SSL证书自动续签与部署完全指南:从托管服务到开源工具全方案解析
数据库
全堆鸿蒙20 小时前
25 数据库设计与表结构规划:5 张表的设计思路
数据库·华为·cocoa·harmonyos
笃行35020 小时前
【金仓数据库产品体验官】_坏得起_实测:备份恢复、PITR 时间穿越与主备切换——KingbaseES V9R3C18 深度体验(三)
数据库
笃行3501 天前
从兼容到进阶:驱动直连、窗口函数与动态 SQL 实测——KingbaseES V9R3C18 深度体验(二)
数据库
笃行3501 天前
MySQL 的 JSON 字段迁到金仓还能用吗?——KingbaseES V9R3C18 JSON 操作符与函数兼容实测
数据库
IpdataCloud1 天前
跨境AI金融风险怎么防?IP风险画像的实战应用指南
数据库·tcp/ip·金融·ip
Alan_751 天前
API 接口慢调用根因定位:从 TCP 建连到数据库 IO 的全栈排查实战
数据库
多巴胺梦想家1 天前
事务与并发控制:当多人同时操作数据库
服务器·数据库·oracle
howard20051 天前
PostgreSQL起步
数据库·postgresql
秋田君1 天前
QT_QT布局详解
开发语言·数据库·qt