学堂 学堂 学堂公众号手机端

MySQL的MVCC底层原理

lewis 1年前 (2024-04-26) 阅读数 14 #技术

MySQL的MVCC底层原理

图1

这是一个account表 有id和name字段

图2


MySQL底层会给表添加2个字段 
一个是trx id(事务id)
一个是roll pointer(回滚指针)

​事务id​

图3

假设一个事务id为60的事务 
往表中插入一条数据
那么这条数据的trx id为当前事务的id 60

注:执行更删改的操作才会生成事务id

​接下来详细说下这个时序图(有先后顺序的)​

图4

​第一个事务​

开启事务
做一个更新test表的操作
做更新的目的是为了生成一个事务id 假设为100

​第二个事务​

开启事务
做一个更新test表的操作
做更新的目的是为了生成一个事务id 假设为200

​第三个事务​

开启事务
做一个更新account表的操作
update accout set name='平凡人笔记' where id = 1
生成一个事务id 假设为300

图5假设这是更新之前的数据

​执行更新操作​

图6

先在MySQL表中插入一条记录
同时把之前的那条记录放到undo log日志(回滚日志)中
新数据中的roll pointer(回滚指针要指向老的那条数据)

​执行时序图中第9步​

MySQL在第一次执行查询语句的时候
select name from account where id =1
会生成一致性视图 叫 read-view(快照视图)
这里面是当前发起的这个查询的时候所有未提交的事务id数组
以及截止目前已创建(包含已提交和未提交)的最大的事务id

图7

​根据以上规则得出第9步首次查询的时候read-view是[100,200],300​

图8

​此时有了版本链和readview​

图9

根据生成的readview去版本链中
从最新的记录
按照一定的规则逐步去找应该显示出来的记录

​图8中的查询这一步骤(对应时序图中的第9步)查询结果​

事务id=100的这个事务未提交
事务id=200的这个事务未提交
事务id=300的这个事务
(update accout set name='平凡人笔记' where id = 1)
提交了

那么结果就是 “平凡人笔记”了

​接着看时序图第10​

update account set name='平' where id =1;

图10

插入一条name为"平"的数据 事务id为100

​时序图11​

update account set name='凡' where id =1;

图11

插入一条name为"凡"的数据 事务id为100

​时序图第12步​

select name from account where id =1
这一步的查询 也有一个read-view

​此时要根据数据库的隔离级别来判断read-view的内容​

如果是可重复读的话 它的read-view就是沿用了当前查询事务第一次查询的时候的readview

图12

如果是读已提交 在每次select的时候都会按最新的情况再生成一次
目前分析的可重复读机制 所以第12步的时候 readview还是[100,200],300

​此时MySQL拿着read-view到最新的版本链逐个去比对查询​

图13

​MySQL底层有一个比对规则​

readview未提交事务数组中最小的事务即min_id=100
已创建的最大的事务id即max_id=300

将所有的事务id分为3个部分

图14

绿色部分 <min_id=100
绿色部分的事务id比未提交事务数组中的最小的事务id还要小
那么绿色部分的事务肯定已经提交了
黄色部分 >=100 && <=300红色部分 >300
继续看图13
先拿到最新的数据

发现它的事务id是100

​此时要结合版本对比规则​

​假设这个select事务有执行过update语句​

那么将会有自己的事务id假设为400
那么这个事务id也会在readview[100,200,400],300
未提交事务数组中
而且跟当前自己的事务id是一样的 那是可见的


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门