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

这篇具有很好参考价值的文章主要介绍了扒开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要返回的是什么内容?是最新一个事务提交后的结果。我们举个例子
    扒开MySQL的源码,探索MVCC实现方式,mysql,数据库
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 >= this
	value. 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 strictly
	smaller (<) than this value.  In other words, this is the
	low water mark". */
	trx_id_t	m_up_limit_id;

	/** trx id of creating transaction, set to TRX_ID_MAX for free
	views. */
	trx_id_t	m_creator_trx_id;

	/** Set of RW transactions that was active when this snapshot
	was taken */
	ids_t		m_ids;

	/** The view does not need to see the undo logs for transactions
	whose 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) const
		MY_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的这条数据就有三个数据版本
扒开MySQL的源码,探索MVCC实现方式,mysql,数据库

  • 如果此时我们再来开启一个事务,m_creator_trx_id=12
    扒开MySQL的源码,探索MVCC实现方式,mysql,数据库那么此时来说,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的源码,探索MVCC实现方式,mysql,数据库

总结

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

相关参考

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

mysql的mvcc机制文章来源地址https://www.toymoban.com/news/detail-802742.html

到了这里,关于扒开MySQL的源码,探索MVCC实现方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【MySQL】MVCC详解与MVCC实现原理(MySQL专栏启动)

    📫作者简介: 小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的

    2023年04月09日
    浏览(29)
  • Mysql MVCC实现

    并发事务可能产生的问题: 读+读,并发读不会有问题 读+写,并发读写可能会发生脏读、不可重复读、幻读 写+写,并发修改同一行数据,可能产生数据丢失(会滚丢失、覆盖丢失)等问题 MVCC(Mutil Version Concurrency Control)多版本并发控制,是一种并发访问的机制(非具体实

    2023年04月23日
    浏览(29)
  • 【进阶篇】MySQL的MVCC实现机制详解

    在数据库领域,对数据进行并发操作是常见的需求。为了保证数据的一致性和事务的隔离性,不同的数据库系统采用了不同的并发控制技术。其中,多版本并发控制(MVCC,Multiversion Concurrency Control)是MySQL中InnoDB存储引擎采用的一种非常重要的并发控制技术。 MVCC通过创建数据

    2024年02月09日
    浏览(31)
  • Jsp+mysql实现简易版购物商城(附源码及数据库)

    目录 实现效果 源代码 数据库文件 结语   实现效果           源代码 login.jsp index.jsp userinfo.jsp addcart.jsp addcartdo.jsp modpro.jsp modprodo.jsp delpro.jsp 数据库文件 shop.sql 结语 再者,记得把jdbc驱动包加到lib目录下,启动tomcat,购物商城小项目就算完成了

    2024年02月03日
    浏览(32)
  • python 实现学生信息管理系统+MySql 数据库,包含源码及相关实现说明~

    1、系统说明 python 编写的学生信息管理系统+MySQL数据库,实现了增删改查的基本功能。 2、数据库说明 本人使用的是 MySQL8.0 版本 数据库端口号为:3306 数据库用户名是:root 数据库名称是:practice 建立的表是:students 3、系统功能 增加学生信息 删除学生信息 修改学生信息 查

    2024年02月11日
    浏览(42)
  • 数据库-MySQL 实战项目——学生选课系统数据库设计与实现(附源码)

            该项目非常适合MySQL入门学习的小伙伴,博主提供了源码、数据和一些查询语句,供大家学习和参考,代码和表设计有什么不恰当还请各位大佬多多指点。  MySQL可视化工具:navicat;  数据库:MySql 5.7/8.0等版本均可;      学生选课系统主要完成某学校教务系统中

    2024年04月08日
    浏览(49)
  • 一零五六、Jsp+mysql 实现学生选课系统(附源码及数据库)

    目录 实现效果 项目代码 数据库 结语 实现效果 login.jsp index.jsp  course_query.jsp  course_selection.jsp   course_withdraw.jsp selection_query.jsp    项目代码 checkSelectionStatus.jsp course_query.jsp course_selection.jsp course_selection_check.jsp course_withdraw.jsp course_withdraw_check.jsp index.jsp login.jsp login_check.jsp se

    2024年02月09日
    浏览(38)
  • 32.商务安全邮箱|JSP+ Mysql设计与实现(可运行源码+数据库+lw)

    推荐阅读100套最新项目 最新ssm+java项目文档+视频演示+可运行源码分享 最新jsp+java项目文档+视频演示+可运行源码分享 最新Spring Boot项目文档+视频演示+可运行源码分享 2024年56套包含java,ssm,springboot的平台设计与实现项目系统开发资源(可运行源代码+设计文档) 目录 文末获

    2024年04月22日
    浏览(21)
  • 基于java Swing 和 mysql实现的购物管理系统(源码+数据库+说明文档+运行指导视频)

    本项目是一套基于java Swing 和 mysql实现的购物管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、项目文档、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,确保可以运行! 技术栈:Jav

    2024年02月10日
    浏览(34)
  • 【MySQL探索之旅】数据库设计以及聚合查询

    📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有限,欢迎各位大佬指点,相互学习进步! 数据库

    2024年04月09日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包