扒开MySQL的源码,探索MVCC实现方式

下载MySQL源码

  • 没有什么比源码更靠谱的了,所以我们先把源码下载下来,后期验证使用
  • MySQL源码下载

MVCC是什么

mvvc全称是multi-version concurrency control(多版本并发控制),主要用于处理读写并发冲突的问题。

MVCC解决了什么问题

我们知道,MySQL的innodb引擎是支持并发的,而支持并发的关键在于行锁,大大提高了并发效率。如果是多个写操作,我们自然是用行锁来解决问题,即多个事务中,必须等第一个事务提交,下一个事务才能提交成功,但是,在有读有写的情况下,比如有三个写事务,三个读事务,那么我这三个读事务难道也应该用锁来控制并发吗?这显然不是最好的方式。
那么怎么办呢。这个时候,就可以使用多版本并发控制来解决问题。

MVCC的实现

mvcc其实也是用空间换时间的一种思想。就是在某个时间点,把这一刻的数据作为快照保存下来,这个快照,其实就是我们说的一致性视图,即ReadView。它保留有关已更改行的旧版本的信息。
当然,具体实现起来并不是这么简单,首先是时间点的确认,就是在什么时候会触发这个操作,第二是保存的是那些数据,因为MySQL不可能把某行记录的所有数据都保存。这些问题我们后面会慢慢说。

隔离级别

innodb的四种隔离级别,即读未提交(ru),读已提交(rc),可重复读(rr),序列化(serializable),更详细的讲解可以参考数据库事务的四大特性以及事务的隔离级别整理

这四种隔离级别,其中ru模式下,每次读取的都是最新的数据,所以用不到mvcc,serializable用锁来实现并发,也用不到mvcc,也就是说,只有rc和rr需要利用readview来实现mvcc。

rc创建readview的时机

我们前面大概提了一下,innodb 保持多版本这个特性是利用readview,那么readview什么时候才会创建呢?对于不同的隔离级别,却有不同的创建时机,

  • rc
    对于读已提交来说,每次的select都会生成一个新的readview,为什么?因为每次select要返回的是什么内容?是最新一个事务提交后的结果。我们举个例子
    在这里插入图片描述
rr创建readview的时机

我们知道rc既然是读已提交,那么rc就不能满足可重复读,那么rr是怎么实现可重复读的呢?在rr模式下,只会在第一次执行查询语句的时候生成一个readview,之后的查询不会再生成readview

结合源码理解ReadView

在我翻看MySQL源码的时候,发现一本很流行的MySQL书籍出现了错误,认为m_up_limit_id是事务列表中的最大值,但源码其实并不是,所以我说,源码是最靠谱的。
在MySQL的源码中,我们找到ReadView的定义,目录文件在mysql-5.7.44/storage/innobase/include/read0types.h
我们看到简化后的这样一段代码

class ReadView {
private:/** The read should not see any transaction with trx id >= thisvalue. In other words, this is the "high water mark". */trx_id_t	m_low_limit_id;/** The read should see all trx ids which are strictlysmaller (<) than this value.  In other words, this is thelow water mark". */trx_id_t	m_up_limit_id;/** trx id of creating transaction, set to TRX_ID_MAX for freeviews. */trx_id_t	m_creator_trx_id;/** Set of RW transactions that was active when this snapshotwas taken */ids_t		m_ids;/** The view does not need to see the undo logs for transactionswhose transaction number is strictly smaller (<) than this value:they can be removed in purge if not needed by other views */trx_id_t	m_low_limit_no;/** AC-NL-RO transaction view that has been "closed". */bool		m_closed;typedef UT_LIST_NODE_T(ReadView) node_t;/** List of read views in trx_sys */byte		pad1[64 - sizeof(node_t)];node_t		m_view_list;
};

接下来我们重点解释一下这几个属性

m_ids

我们来看一下这段代码,这段代码体现了插入m_ids的时机,就是生成readview之后,要如果当前的m_creator_trx_id>0,则插入到m_ids。

ReadView::copy_complete()
{ut_ad(!trx_sys_mutex_own());if (m_creator_trx_id > 0) {m_ids.insert(m_creator_trx_id);}if (!m_ids.empty()) {/* The last active transaction has the smallest id. */m_up_limit_id = std::min(m_ids.front(), m_up_limit_id);}ut_ad(m_up_limit_id <= m_low_limit_id);/* We added the creator transaction ID to the m_ids. */m_creator_trx_id = 0;
}

前面我们知道了生成readview的时机,那么m_creator_trx_id又是什么东西呢,m_creator_trx_id为什么有时候大于0,有时候等于0,我们继续看

m_creator_trx_id

m_creator_trx_id是创建该readview的事务id,从前面代码我们也可以看到m_creator_trx_id的默认值是0,只有对表中的记录做修改的时候,才会分配一个唯一的事务id,那么此时,我们至少明白了两点,第一个是m_ids里面是事务id的列表,并且这些事务都对数据做了修改,第二个是只读的时候分配的m_creator_trx_id是0,当前的事务创建的readview对自己肯定是可见的

m_low_limit_id

目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。大于等于这个 ID 的数据版本均不可见 ;

m_up_limit_id

活跃事务列表 m_ids 中最小的事务 ID,任何一个数据版本,如果它是的事务id是小于m_up_limit_id的,那么它是可见的。最简单的例子,读事务的事务id是0,那么它肯定是小于m_up_limit_id的,

判断是否可见的源码如下

/** Check whether the changes by id are visible.@param[in]	id	transaction id to check against the view@param[in]	name	table name@return whether the view sees the modifications of id. */bool changes_visible(trx_id_t		id,const table_name_t&	name) constMY_ATTRIBUTE((warn_unused_result)){ut_ad(id > 0);//如果readview就是m_creator_trx_id创建的,则可见if (id < m_up_limit_id || id == m_creator_trx_id) {return(true);}check_trx_id_sanity(id, name);if (id >= m_low_limit_id) {return(false);//如果没有活跃的事务,则数据可见~~删除线格式~~ } else if (m_ids.empty()) {return(true);}const ids_t::value_type*	p = m_ids.data();return(!std::binary_search(p, p + m_ids.size(), id));}

版本链

我们前面介绍了readview,以及readview对那些事务id可见,那么对于一行记录,有三个隐藏的字段来辅助实现了mvcc的功能,

  • DB_TRX_ID
    最新的事务id
  • DB_ROLL_PTR
    我们说版本链,是靠什么把这些版本链接起来的呢,就是这个回滚指针,指向的是该行的undolog。undolog的记录了数据修改前的样子

我们前面说了事务id,那么这个事务id和readview又是怎么使用的呢,我们来看下面的数据的版本链
比如我在事务1中执行以下sql

drop table student;
create table student(id int auto_increment,name varchar(20) ,primary key (id)
);
insert into student values(1,'张三');# 2.设置隔离级别  读已提交
set session transaction isolation level read committed;start transaction;update student set name='张三丰' where id=1;
update student set name='张四丰' where id=1;

那么此时,id为1的这条数据就有三个数据版本
在这里插入图片描述

  • 如果此时我们再来开启一个事务,m_creator_trx_id=12
    在这里插入图片描述那么此时来说,m_ids里面存在的就是11 和12 ,m_low_limit_id就是12+1=13,m_up_limit_id=11,那么对于事务12来说,因为DB_TRX_ID(最新的事务id)就是12 和它的m_creator_trx_id是相等的,所以李四这个数据对事务12是可见的。
  • 我再开启一个读事务3,该事务并没有操作数据所以m_creator_trx_id是0,那么它读的是哪个版本的数据呢,首先读12,不满足,因为事务12出现在活跃的m_ids里面,同理11也不满足,到了10的时候,满足了条件 id<m_up_limit_id,所以这个查询可以看到张三这条记录

在这里插入图片描述

总结

通过阅读源码和实操,我们了解了MySQL是怎么在无锁的情况下怎么保证了多版本控制,就是在数据发生变化的时候,将变化前的内容以undo-log的形式保存了下来,然后通过DB_ROLL_PTR将多个版本链起来,来提高表的并发读写。但是带来的问题,最明显的就是对内存的需求更高,cpu和io开销更大了,同理垃圾回收开销也随着变大。而且对于大事务来说,数据版本过多可能导致性能降低等问题。

相关参考

MVCC原理分析 + 源码解读 – 必须说透

mysql的mvcc机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/623815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据开发之Hive(企业级调优)

第 10 章&#xff1a;企业级调优 创建测试用例 1、建大表、小表和JOIN后表的语句 // 创建大表 create table bigtable(id bigint, t bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by \t; //…

Asp .Net Core 系列:基于 Swashbuckle.AspNetCore 包 集成 Swagger

什么是 Swagger? Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。它提供了一种规范的方式来定义、构建和文档化 RESTful Web 服务&#xff0c;使客户端能够发现和理解各种服务的功能。Swagger 的目标是使部署管理和使用功…

Halcon滤波器 laplace 算子

Halcon滤波器 laplace 算子 使用laplace 算子对图像进行二次求导&#xff0c;会在边缘产生零点&#xff0c;因此该算子常常与zero_crossing算子配合使用。求出这些零点&#xff0c;也就得到了图像的边缘。同时&#xff0c;由于laplace算子对孤立像素的响应要比对边缘或线的响应…

【SpringBoot系列】JDK动态代理

🤵‍♂️ 个人主页:@香菜的个人主页,加 ischongxin ,备注csdn ✍🏻作者简介:csdn 认证博客专家,游戏开发领域优质创作者,华为云享专家,2021年度华为云年度十佳博主 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收…

kafka除了作为消息队列还能做什么?

Kafka 最初是为大规模处理日志而构建的。它可以保留消息直到过期&#xff0c;并让各个消费者按照自己的节奏提取消息。 与其之前的竞品不同&#xff0c;Kafka 不仅仅是一个消息队列&#xff0c;它还是一个适用于各种情况的开源事件流平台。 让我们回顾一下流行的 Kafka 用例。 …

C语言经典算法之冒泡排序算法

目录 前言 建议&#xff1a; 简介&#xff1a; 一、代码实现 二、时空复杂度 时间复杂度&#xff1a; 空间复杂度&#xff1a; 总结&#xff1a; 前言 建议&#xff1a; 1.学习算法最重要的是理解算法的每一步&#xff0c;而不是记住算法。 2.建议读者学习算法的时候…

CNN:Convolutional Neural Network(下)

目录 1 CNN 学到的是什么 1.1 Convolution 中的参数 1.2 FFN 中的参数 1.3 Output 2 Deep Dream 3 Deep Style 4 More Application 4.1 AlphaGo 4.2 Speech 4.3 Text 原视频&#xff1a;李宏毅 2020&#xff1a;Convolutional Neural Network 本博客属于学…

计算机毕业设计----SSH实现简单在线听音乐收藏管理系统

项目介绍 项目分为管理员与普通用户两种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 管理员登录,用户管理,歌曲管理等功能。 用户角色包含以下功能&#xff1a; 按分类查看,添加歌单,用户登录等功能。 环境需要 1.运行环境&#xff1a;最好是java jdk 1.8&…

shell从入门到精通

系列文章目录 shell从入门到精通 shell从入门到精通 系列文章目录一、diff 用法 &#xff08;一般作补丁,用补丁的方式更新脚本&#xff09;1.1参数a添加1.2 参数c更改1.3参数d删除1.4参数a和d的对比1.5参数b&#xff08;忽略空格&#xff09;1.6 参数B&#xff08;忽略空行&a…

打造创新的金融数据平台,加速数字化和智能化转型丨PingCAP 官网金融行业专区上线

自诞生以来&#xff0c;TiDB 的原生分布式架构在强一致性、高可用性和可扩展性等方面与金融级业务需求高度契合&#xff0c;早期版本即为包括北京银行在内的金融用户提供服务。 TiDB 的核心能力始终源自与中国金融用户的共同创造。作为金融级分布式数据库&#xff0c;TiDB 在国…

【pytorch】使用pytorch构建线性回归模型-了解计算图和自动梯度

使用pytorch构建线性回归模型 线性方程的一般形式 衡量线性损失的一般形式-均方误差 pytorch中计算图的作用和优势 在 PyTorch 中&#xff0c;计算图&#xff08;Computational Graph&#xff09;是一种用于表示神经网络运算的数据结构。每个节点代表一个操作&#xff0c;例如…

药物“出气”可知|ZL-005大小鼠雾化给药仪

雾化吸入给药是一种通过装置使药物进入肺部局部或全身发挥作用的给药方式。相较于口服药剂&#xff0c;雾化吸入给药可避免首过效应和药剂破坏&#xff0c;提高药物生物利用度。 而ZL-005大小鼠雾化给药仪&#xff0c;则是新一代小动物雾化装置的理想选择&#xff0c;可完成动…

JavaWeb之Redis

31、Redis 31.1、Redis概述 概念&#xff1a;redis是一款高性能的NOSQL系列的非关系性数据库 什么是NOSQL NoSQL(NoSQL Not Only SQL)&#xff0c;意即“不仅仅是SQL”&#xff0c;是一项全新的数据库理念&#xff0c;泛指非关系型的数据库。 随着互联网web2.0网站的兴起&a…

MIT_线性代数笔记:第 26 讲 复矩阵;快速傅里叶变换

目录 复向量 Complex vectors复矩阵 Complex matrices傅里叶变换 Fourier transform快速傅里叶变换 Fast Fourier transform 实矩阵也可能有复特征值&#xff0c;因此无法避免在矩阵运算中碰到复数&#xff0c;本讲学习处理复数矩阵和复向量。 最重要的复矩阵是傅里叶矩阵&…

电力能源监测管理系统,在医院中有哪些作用?

随着经济全球化的发展&#xff0c;节能减排成为当前社会发展必须关注的问题。电力能源监测管理系统&#xff0c;可以分析电力管理能源的现状&#xff0c;并根据现状提出对应的策略&#xff0c;为快速高效建成绿色智能化医院提供有力支撑和技术保障。 医院能源管理现状 1、人力…

Java零基础教学文档第四篇:HTML_CSS_JavaScript(2)

【HTML】 【主要内容】WEB: 1&#xff0e;Web前端简介 2&#xff0e;创建第一个前端项目 3&#xff0e;相关标签详解 4&#xff0e;表格标签详解 5&#xff0e;表单标签详解 6&#xff0e;框架和实体字符 【学习目标】 1. Web前端简介 1.1 为什么要学习Web前端&#…

Windows10 Docker Desktop安装

一、简介 Docker Desktop是Docker公司推出的一款桌面应用程序&#xff0c;它提供了一个用户友好的界面&#xff0c;方便开发人员在本地环境中使用容器技术。 容器是一种轻量级的虚拟化技术&#xff0c;可以将应用程序和其依赖项打包在一起&#xff0c;形成一个独立、可移植的…

Linux学习之网络编程1(纯理论)

写在前面 刚刚更新完Linux系统编程&#xff0c;特别推荐大家去看的Linux系统编程&#xff0c;总共44个小时&#xff0c;老师讲的非常好&#xff0c;我是十天肝完的&#xff0c;每天大概看20集&#xff0c;每天还要以写blog的形式来写笔记来总结一下&#xff0c;虽然这十天有点…

适用于Mac电脑的 iOS 设备管理器选 iTunes 还是iMazing?

mac上有没有好用的ios设备管理器&#xff1f; 因为工作的关系&#xff0c;一共使用3部苹果手机&#xff0c;资料很杂很多也很乱&#xff0c;想整理也不知道从何下手&#xff0c;有人推荐【iTunes】&#xff0c;有人推荐【iMazing】&#xff0c;该如何选择呢&#xff1f; 一、i…

架构师 - 架构师是做什么的 - 学习总结

架构师核心定义 架构师是什么 架构师是业务和技术之间的桥梁 架构师的核心职责是消除不确定性、和降低复杂性 架构设计环 架构师的三个核心能力 架构师的三个关键思维 架构师主要职责 架构设计 Vs 方案设计 架构设计前期 主要任务 澄清不确定性 明确利益干系人的诉求消除冲…