MVCC和BufferPool缓存机制

文章目录

    • 1. MVCC多版本并发控制机制
    • 2. BufferPool缓存机制

1. MVCC多版本并发控制机制

Mysql可以在可重复读隔离级别下可以保证事务较高的隔离性,这个隔离性是由MVCC机制来保证的,对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性,避免了频繁加锁互斥,而在Mysql在读已提交和可重复读隔离级别下都实现了MVCC机制。
undo日志版本链与read view机制详解
undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完后,Mysql会保留修改前的数据undo回滚日志,并且用两个隐藏字段trx_id(事务ID)和roll_pointer(会滚指针)把这些undo日志串联起来形成一个历史记录版本链。

trx_id:表示对数据修改的事务的ID
roll_pointer:指向被修改数据的上一个版本

在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view,该视图在事务结束之前都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成),这个视图由执行查询时所有未提交事 id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。

注意:begin/start transaction命令并不是一个事务的起点,在执行到它们之后的第一个修改操作InnoDB表的语句时事务才算是真正的启动,此时事务会向Mysql申请事务ID,mysql内部是严格按照事务的启动顺序来分配事务ID的

在这里插入图片描述

版本链比对规则:

  1. 如果 row 的 trx_id 落在绿色部分( trx_id<min_id ),表示这个版本是已提交的事务生成的,这个数据是可见的;
  2. 如果 row 的 trx_id 落在红色部分( trx_id>max_id ),表示这个版本是由将来启动的事务生成的,是不可见的(若 row 的 trx_id 就是当前自己的事务是可见的);
  3. 如果 row 的 trx_id 落在黄色部分(min_id <=trx_id<= max_id),那就包括两种情况
    a. 若 row 的 trx_id 在视图数组中,表示这个版本是由还没提交的事务生成的,不可见(若 row 的 trx_id 就是当前自
    己的事务是可见的);
    b. 若 row 的 trx_id 不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

read-view执行原理案例分析
这里首先列出了五个事务的sql语句执行情况,如下:
在这里插入图片描述

由上图可见,总共有五个事务,事务的id为100,200,300,1,2,下面我们就来逐步分析:

  1. 首先事务300执行update account set name = 'lilei300' where id = 1;然后提交。接着事务ID为1的事务执行select name from account where id = 1;

我们可以很简单的看出查询结果为lilei300,那为什么会是lilei300。首先我们可以看出此时的undo.log的日志版本链的情况是这样的:

在这里插入图片描述

其中蓝色为最新的数据,红色为老数据。然后mysql会维护一个事务集,如下:

在这里插入图片描述

然后mysql会从日志版本链的最新的数据开始向下遍历,这个例子先从上面第一个蓝色的开始,取出其事务ID为300,到事务集合中去比对,发现位于黄色的区域(即有可能还是未提交),然后判断是否在事务ID的read-view数组中(该数组前面说过是由活跃事务的ID数组以及最大已提交事务组成),目前由第一张事务的执行情况图我们可以看出,目前事务ID为1的read-view为[100,200],300构成,而300没在read-view的活跃数组中,所以300对数据进行的更改对事务1是可见的,所以日志版本链就不需要向下遍历了,查询的结果即为lilei300。

  1. 然后ID为100的事务又执行了两条更新语句,分别为update account set name = 'lilei1' where id = 1;update account set name = 'lilei2' where id = 1;,接着ID为1的事务再次执行了查询select name from account where id = 1;

同样从会滚日子链开始分析,蓝色同样为最新的数据,红色为老数据,目前的日子版本链的情况如下所示:

在这里插入图片描述

首先从最新的数据开始便利日志版本链,首先拿到ID为100的数据,比对事务集合,其同样落在黄色区域,然后事务ID1比较其readview,发现其落在了活跃数组[100,200]中(注意除非一些特殊情况ID为1的事务对数据进行了一些修改,其readview在整个过程中一般是不变的,虽然每次执行一次查询语句都会重新生成read-view),所以其对ID为1的事务是不可见的。然后接着向下遍历,知道遍历到ID为300的事务,发现其是可见的,所以查询到的数据同样是lilei300。后面的过程同样是按照这个过程分析。

mysql通过这个机制在RR隔离级别下实现了事务的可重复读而不用加锁。而在读已提交的情况下Mysql同样实现了MVCC机制,不同于RR级别,在读已提交的隔离级别下,每当一个事务被提交,其它事务相应的read-view会及时更新。

2. BufferPool缓存机制

InnoDB引擎SQL执行的BufferPool缓存机制如下所示:

在这里插入图片描述
对上图进行分析:

  1. 首先客户端执行sql语句update t set name='zhuge666' where id=1
  2. 然后经过连接器进行客户端的权限验证(判断该客户端是否有修改该条数据的权限)
  3. 然后通过分析器对sql语句进行词法分析
  4. 接着经过优化器来生成sql执行计划以及选择合适的索引
  5. 最后来到执行器开始真正执行sql(InnoDB层)
  • 首先InnoDB会将id为1的数据所在的页加载到BufferPool中
  • 然后将要更新的那条数据旧的值写入到undo日志中(用于后期会滚)
  • 然后更新BufferPool中的缓存数据
  • 然后将更新情况写入到redo日志缓存中
  • 客户端准备提交事务
  • 首先redo日志写入到磁盘
  • binlog(主要用于回复数据库磁盘中的数据)日志写入磁盘
  • 写入commit标记到redo日志文件中,提交事务完成,该标记为了保证事务提交后redo于binlog日志的一致性。
  • Mysql后台IO线程随机以page为单位将更新后的数据写入到磁盘

以上便是该sql语句执行的整个过程,但对于上面的过程可能还会存在下面这些问题:

  1. InnoDB体系结构是什么样子的?
    在这里插入图片描述
    InnoDB存储引擎有多个内存块,可以认为这些内存块共同组成了一个大的内存池,负责如下工作:
  • 维护所有进程/线程需要访问多个内部数据结构
  • 缓冲磁盘上的数据,方便快速读取(bufferPool),同时在对磁盘文件的数据修改之前在这里缓存
  • 重做日志缓存(redo.log)

后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存是最近的数据。此外将修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能够恢复到正常运行的状态。

  1. Mysql的bufferpool的组成?

在这里插入图片描述
3. Mysql是如何对缓冲池进行管理?

通常来说数据库中的缓冲池是通过LRU算法来进行管理的,即最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。但InnoDB使用的并不是朴素的LRU算法,而是在LRU列表中加入了midpoint的位置,midpoint将LRU列表的数据页分为热数据和冷数据两部分。(这部分还是比较复杂的)

  1. rode日志的刷新时机?
  • Master Thread每一秒将重做日志缓存刷新到重做日志文件
  • 每个事务提交时会将重做日志缓存刷新到重做日志文件
  • 当重做日志缓存剩余空间下雨1/2时,重做日志缓存刷新到重做日志文件
  1. 为什么Mysql不能直接更新磁盘上的数据而且设置这么一套复杂的机制来执行SQL了?

因为来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据性能可能相当差。因为磁盘随机读写的性能是非常差的,所以直接更新磁盘文件是不能让数据库抗住很高并发的。 Mysql这套机制看起来复杂,但它可以保证每个更新请求都是更新内存BufferPool,然后顺序写日志文件,同时还能保证各种异常情况下的数据一致性。 更新内存的性能是极高的,然后顺序写磁盘上的日志文件的性能也是非常高的,要远高于随机读写磁盘文件。 正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几千的读写请求。

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

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

相关文章

SpringCloud(三)Sentinel、Seata、多级缓存

文章目录 Sentinel雪崩问题Sentinel与Hystrixsentinel使用案例限流规则流控模式流控效果热点参数限流 隔离和降级Feign整合Sentinel线程隔离熔断降级 授权规则与规则持续化自定义异常结果规则管理模式 Seata分布式事务问题理论基础CAP定理BASE理论 Seata架构部署TC服务微服务集…

软件测试「转行」答疑(未完更新中)

⭐ 专栏简介 软件测试行业「转行」答疑&#xff1a; 如果你对于互联网的职业了解一知半解&#xff01;不知道行业的前景如何&#xff1f;对于众说纷纭的引流博主说法不知所措&#xff01;不确定这个行业到底适不适合自己&#xff1f; 那么这一篇文章可以告诉你所有真实答案&a…

什么是全流程的UI设计?它与单页面的视觉设计有什么区别?

在软件产品研发流程中&#xff0c;产品交互设计一般是根据项目需求&#xff0c;做出设计方案&#xff0c;以求解决某个问题。而全流程的设计不再局限于短暂或者单个页面的视觉优化&#xff0c;而是追求持续性地参与&#xff0c;以全局性整体性地提升产品体验。 在软件内的信息传…

高级深入--day29

入门案例 学习目标 创建一个Scrapy项目定义提取的结构化数据(Item)编写爬取网站的 Spider 并提取出结构化数据(Item)编写 Item Pipelines 来存储提取到的Item(即结构化数据)一. 新建项目(scrapy startproject) 在开始爬取之前,必须创建一个新的Scrapy项目。进入自定义的项目目…

WPF向Avalonia迁移(一、一些通用迁移项目)

通用变更 WPF&#xff1a;Visibility 其他参考文档 WPF&#xff1a; <TextBlock Visibility"Visible"/><TextBlock Visibility"Collapsed"/><TextBlock Visibility"Hidden"/>Avalonia &#xff1a; <TextBlock IsVisib…

【广州华锐互动】VR线上播控管理系统让虚拟现实教学效果更加显著

随着科技的不断发展&#xff0c;虚拟现实(VR)技术已经逐渐走进我们的生活&#xff0c;尤其在教育领域&#xff0c;VR技术的应用为学生提供了全新的学习体验。 广州华锐互动作为一家成立16年的老牌VR公司&#xff0c;开发了不少VR教学课件&#xff0c;包括物理、化学、农林、土木…

mybatis配置entity下不同文件夹同类型名称的多个类型时启动springboot项目出现TypeException源码分析

记录问题&#xff1a;当配置了 mybatis.type-aliases-packagecom.runjing.erp.entity 配置项时&#xff0c;如果entity文件夹下存在不同子文件夹下的同名类型时&#xff0c;mybatis初始化加载映射时会爆出org.apache.ibatis.type.TypeException&#xff1a; The alias TestDemo…

Android用户登录与数据存储:从权限请求到内外部存储的完整实践【完整实践步骤、外部存储、内部存储】

步骤 1: 登录页面布局 在 MainActivity 中实现用户登录功能&#xff0c;首先创建一个布局文件 activity_main.xml 包含用户名和密码的输入字段以及登录按钮。 <!-- activity_main.xml --> <LinearLayoutxmlns:android"http://schemas.android.com/apk/res/andr…

【Java题】模拟下载进度条

目录 一&#xff1a;题目 二&#xff1a;解析 1.匿名内部类 2.lambda 三&#xff1a;结果 一&#xff1a;题目 使用匿名内部类&#xff0c;模拟下载过程进度条&#xff0c;体会回调函数的作用。 1. 定义 DownloadListener 接口&#xff0c;包含一个包含 void progressU…

基于vue框架的uniapp小程序开发发现了新大陆

项目场景&#xff1a; 在基于vue框架的uniapp小程序开发中&#xff0c;在页面跳转时&#xff0c;当前页路径带参数&#xff0c;在跳转页中接受数据除了用官方推荐的保留当前页面&#xff0c;跳转到应用内的某个页面&#xff0c;使用onLoad(option)接受数据&#xff0c;但是我发…

webpack不同环境下使用CSS分离插件mini-css-extract-plugin

1.背景描述 使用mini-css-extract-plugin插件来打包css文件&#xff08;从css文件中提取css代码到单独的文件中&#xff0c;对css代码进行代码压缩等&#xff09;。 本次采用三个配置文件&#xff1a; 公共配置文件&#xff1a;webpack.common.jsdev开发环境配置文件&#x…

IDEA 2021.2.2设置自动热部署

1.导入包坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency> 2.pom.xml添加piugins插…