通俗易懂的MySQL事务及MVCC原理,我先收藏了

本文详细解释了MySQL中的Undolog(UndoLog)如何在事务回滚时恢复数据,以及trx_id、row_id和roll_pointer在事务管理中的作用。同时介绍了MVCC在ReadView和不同隔离级别下的运用。此外,还提到了Kafka在分布式系统中的重要性及源码阅读资源。
摘要由CSDN通过智能技术生成

undo log主要用于事务回滚时恢复原来的数据

mysql在执行sql语句时,会将一条逻辑相反的日志保存到undo log中。因此,undo log中记录的也是逻辑日志。

当sql语句为insert时,会在undo log中记录本次插入的主键id。等事务回滚时,delete此id即可。

当sql语句为update时,会在undo log中记录修改前的数据。等事务回滚时,再执行一次update,得到原来的数据。

当sql语句为delete时,会在undo log中记录删除前的数据。等事务回滚时,insert原来的数据即可。

数据库事务四大特性中的原子性,即事务具有不可分割性,要么全部成功,要么全部失败,其底层就靠undo log实现。在某一步执行失败时,会对之前事务的语句进行回滚。

对数据库中的日志完全不熟悉的话,可以看我的另外一篇文章数据库日志——binlog、redo log、undo log扫盲

行的隐藏列

=====

在数据库中的每一行上,除了存放真实的数据以外,还存在着3个隐藏列——row_id、trx_id与roll_pointer。

row_id,行号

==========

如果当前表有整数类型的主键,则row_id就是主键的值。

如果没有整数类型的主键,则mysql会按照字段顺序选择一个非空的整数类型的唯一索引作为row_id。

如果mysql没有找到,则会自动生成一个自动增长的整数作为row_id。

那row_id和今天的MVCC有什么关系呢?

不能说一点没有吧,只能说毫无关系。

trx_id,事务号

===========

当一个事务开始执前,mysql会为这个事务分配一个全局自增的事务id。

之后该事务对当前行进行的增、删、改操作时,都会将自己的事务id记录到trx_id中。

roll_pointer,回滚指针

==================

事务对当前行进行改动时,会将旧数据写入进undo log中,再将新数据写入当前行,且当前行的roll_pointer指向刚才那个undo log,因此可以通过roll_pointer找到该行的前一个版本。

当一直有事务对该行改动时,就会一直生成undo log,最终将会形成undo log版本链

Undo log版本链

===========

一开始,我们使用以下语句创建一个stduent表

CREATE TABLE student (

id INT ( 11 ) NOT NULL AUTO_INCREMENT,

name VARCHAR ( 255 ) NOT NULL,

age INT ( 11 ) NOT NULL,

PRIMARY KEY ( id ) USING BTREE

) ENGINE = INNODB;

现在开启第1个事务,事务id为1,执行以下插入语句。

INSERT INTO student VALUES ( 1, “a”, 24 );

那么当前行的一个示意图如下:

因为该数据是新插入的,因此它的roll_pointer指向的undo log为空。

接着开启第2个事务,分配的事务id是2,执行以下修改命令。

UPDATE student SET NAME = ‘b’ WHERE id = 1;

现在的示意图变为:

当开启第3个事务,分配到事务id是3,执行以下修改命令。

UPDATE student SET age = 25 WHERE id = 1;

示意图变为:

每一个事务对该行改动时,都会生成一个undo log,用于保存之前的版本,之后再将新版本的roll_pointer指向刚才生成的undo log。

因此roll_pointer可以将这些不同版本的undo log串联起来,形成undo log版本链。

ReadView

========

首先需要理解一下快照读与当前读

快照读:简单的select查询,即不包括 select … lock in share mode, select … for update,可能会读到数据的历史版本。

当前读:以下语句都是当前读,总是读取最新版本,会对读取的最新版本加锁。

  • select … lock in share mode

  • select … for update

  • insert

  • update

  • delete

在事务执行每一个快照读或事务初次执行快照读时,会生成一致性视图,即ReadView。

ReadView的作用是,判断undo log版本链中的哪些数据对当前事务可见。

ReadView包含以下几个重要的参数:

m_ids

======

在创建ReadView的那一刻,mysql中所有未提交的事务id集合。

min_trx_id

============

m_ids中的最小值

max_trx_id

============

mysql即将为下一个事务分配的事务id,并不是m_ids中的最大值。

creator_trx_id

================

即创建此ReadView的事务id

简要的示意图如下:

那么事务在执行快照读时,可以通过以下的规则来确定undo log版本链上的哪个版本数据可见。

如果当前undo log的版本的trx_id<min_trx_id,说明该版本对应的事务在生成ReadView之前就已经提交了,因此是可见的。

如果当前undo log的版本的trx_id≥max_trx_id,说明该版本对应的事务在生成ReadView之后才开始的,因此是不可见的。

如果当前undo log的版本的trx_id∈[min_trx_id,max_trx_id),如果在这个范围里,还要判断trx_id是否在m_ids中:

在m_ids中,说明版本对应的事务未提交,因此是不可见的。

不在m_ids中,说明版本对应的事务已经提交,因此是可见的。

如果当前undo log的版本的trx_id=creator_trxt_id,说明事务正在访问自己修改的数据,因此是可见的。

当undo log版本链表的头结点数据被判定为不可见时,则利用roll_pointer找到上一个版本,再进行判断。如果整个链表中都没有找到可见的数据,则代表当前的查询找不到数据。

MVCC在四种隔离级别下的区别

===============

在Read Uncommitted级别下,事务总是读取到最新的数据,因此根本用不到历史版本,所以MVCC不在该级别下工作。

在Serializable级别下,事务总是顺序执行。写会加写锁,读会加读锁,完全用不到MVCC,所以MVCC也不在该级别下工作。

真正和MVCC兼容的隔离级别是Read Committed(RC)与Repeatable Read(RR)

MVCC在RC与RR级别下的区别,在于生成ReadView的频率不同。

在RC级别下,当前事务总是希望读取到别的事务已经提交的数据,因此当前事务事务会在执行每一次快照读的情况下都会去生成ReadView,实时更新m_ids,及时发现那些已经提交的事务。

在RR级别下,当前事务当然也能够读取到别的事务已经提交的数据,但为了避免不可重复读,因此只会在执行第一次快照读的情况下去生成ReadView,之后的快照读会一直沿用该ReadView。

举个栗子:

在RC级别下

一开始,事务id为1的事务往表里插入了一条数据,版本链如下:

这个时候,开启事务id为2的事务,关闭自动提交模式。先执行一次select *查询,生成的ReadView如下

m_ids={2},min_trx_id=2,max_trx_id=3,creator_trx_id=2

由于该条数据的trx_id<min_trx_id,说明该版本对应的事务在生成ReadView之前就已经提交了,因此是可见的。

因此,事务2能直接查到该数据。

现在开启事务3,事务id为3,将该条数据的name改为b,并自动提交,版本链如下:

这个时候,事务2再次select *查询,由于处于RC级别下,会再次生成ReadView,此时的ReadView如下:

m_ids={2},min_trx_id=2,max_trx_id=4,creator_trx_id=2

由于最新版本的trx_id∈[2,4)且trx_id不在m_ids中,说明该版本的数据已经提交,因此是可见的,所以事务2能查到最新的数据。

而处于RR级别下:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

就这一次!拼多多内部架构师培训Kafka源码笔记(现已绝版)

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
取)**

img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

[外链图片转存中…(img-FTsvPjMZ-1712520016224)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值