Mysql-Mvcc原理

news/2024/10/3 17:09:40

0.背景

在mysql的并发访问中,有几个典型的并发场景:

  • 读-读:无需处理,都是读取,不会对数据有影响。

  • 写-写:由于都涉及到数据的修改,不可能乱改,所以没有较好的方式来处理,一般都得加锁。

  • 读-写:读写场景,加锁当然ok。不过读操作是很频繁的,一但写数据就不让读取了,这种情况是让人很难受的。

    Mysql的前辈们通过Mvcc的方案来优化这个问题。通过Mvcc,可以无锁的方式兼顾读写的场景,无论数据是否在修改,都不会阻塞读操作。

1.快照读和当前读

mysql读取数据有当前读快照读的区分

数据嘛,无非就是增删改查,读取的时候,由于要考虑并发,可能会有别的事务在修改这个数据。

然后呢,Mysql引入了一个快照的概念,快照嘛,就跟照片一样,将一个临时的状态记录下来。

所以上面的2个呆板的词语,可以理解为:

  • 当前读:读取最新的数据
  • 快照读:读取快照时的数据

回到最开始的问题,写数据的时候,一定要阻塞吗?写数据的时候,可不可以读数据。

读数据,我不是读取最新的数据吗?我读取快照那个瞬间的数据有啥意思?

这个点在于我们处在当前事务的角度来看,事务的基本特性是ACID。

如果我们在一个事务里面,读取到的数据都是混乱的,那还能操作吗?

快照读的意义就是解决之前提到的不可重复读和幻读这些问题,来保证同一事务中的数据一致性。

关键点:是为了在当前事务中,保证数据读取的一致性。

1.1 当前读

对读取的记录加锁,读取最新的数据,并阻塞其他事务同时修改。

  • 读取的是数据库中当前的最新数据。
  • 如果其他事务正在对数据进行修改,在当前读中读取到的是已经提交的最新版本数据,而不考虑其他事务的未提交变更。
  • 在当前读中,事务读取数据时会获取短暂的共享锁,以确保其他事务在该事务读取数据期间不能修改数据,但不阻塞其他事务的读取操作。

场景:

-- 更新
-- 更新嘛,必须拿着最新的记录进行更新,不能拿个快照数据来更新,假设别的事务把数据给你删除了,还更新啊?
update ...-- 删除
delete ...-- 插入
insert ...-- 共享锁
select ... lock in share mode-- 独占锁
select ... for update

1.2 快照读

读数据不需要进行加锁,也不会阻塞和被其他事务阻塞。

  • 快照读是指事务在执行查询操作时,读取的是事务开始时的一致性快照,即查询操作在事务启动时所能看到的数据版本。
  • 快照读不会受到其他事务正在修改数据的影响,读取的是一致性的数据快照。
  • 在快照读中,事务读取数据时不会获取锁,因此不会阻塞其他事务的读取或写入操作。

场景:

-- 单纯的select操作(不包括上面的共享锁和独占锁)
select ...

2.Mvcc关键点

MVCC(Multi-version concurrency control 多版本并发控制)是一种并发控制机制,用于在事务并发执行时保证数据的一致性和隔离性,它就是快照读的一种解决方案。

2.1 隐藏字段

在Mysql中,事务id是默认递增的。

在数据库行记录中,存在一些隐藏字段,例如DB_TRX_IDDB_ROLL_PTRDB_ROW_ID等。

  • db_trx_id

    6-byte的事务ID,处理这条数据对应的事务id。

  • db_roll_ptr

    7-byte的回滚指针,就是指向行记录的上一个版本。

  • db_row_id

    6-byte的隐藏主键。如果数据表中没有主键,那么InnoDB会自动生成单调递增的隐藏主键(表中有主键或者非NULL的UNIQUE键时都不会包含 DB_ROW_ID列)。

DB_TRX_IDDB_ROLL_PTR这2个字段是Mvcc涉及到的主要字段。

image-20240507162752391

2.2 Undo Log(回滚日志)

在Mysql中进行数据修改时,会在undo log中记录存量的数据值,多个版本的数据进行记录后,就形成了一个版本链。

例如:回滚指针会指向上个版本的数据记录,例如在事务101、102中先后将name修改为了yang1和yang2。

image-20240507162812591

这个设计,方便实现以下功能。

  • 方便回滚,直接根据回滚指针找到之前的数据进行回退。
  • 在Mvcc中用于读取数据(后文描述)

2.3 Read View(读视图)

Read View(读视图)是进行查询操作时生成的一个视图,事务开始前会创建Read View(RC、RR级别有差异),根据生成的这个Read View,判断读取哪个版本的数据。

额,当做是个临时对象好了,存几个值方便后续进行比较。

包含4个关键字段

活跃事务:创建了事务但是还没提交

  • creator_trx_id:创建这个Read View的事务ID,即创建者的事务ID。
  • m_ids:创建ReadView时,活跃事务的ID集合。
  • min_trx_id:创建ReadView时,活跃事务中最小事务ID。
  • max_trx_id:创建ReadView时,当前最大事务ID+1(应该分配给下一个事务的id值)。

image-20240507173748434

这里要注意下min和max跟m_ids的关系:

1.min_trx_id是m_ids活跃事务集合中的最小值。

2.max_trx_id通常跟m_ids没关系,max_trx_id是在创建ReadView时,计划分配给下一个事务的ID值。

3.min_trx_id <= m_ids < max_trx_id

好,那我为啥要关注min_trx_id和max_trx_id呢?

ReadView记录了我们当前这瞬间的一些快照信息。

min_trx_id是快照时的最小活跃事务id,最小的活跃事务呀,如果一个事务id比这个min_trx_id小的话,这个事务在快照时就肯定被提交过了,相当于一个过去的事件,所以一定是可以看到的。

max_trx_id是快照时的待分配事务id,最大的事务id,如果一个事务id比这个max_trx_id还要大的话,这个事务快照时肯定还没提交,相当于一个未来的事件,那么肯定是不可见的。

2.3.1 RC和RR的差异

  • read committed (读已提交):事务每次select时都创建ReadView
  • repeatable read (可重复读):事务第一次select时创建ReadView,后续一直使用。

2.4 可见性判断

2.4.1 事务ID比较可见性

每个数据版本都有一个db_trx_id,代表创建该版本的事务ID(db_trx_id)。

db_trx_id与和ReadView中的参数进行比较,以确定该版本对当前事务的可见性。

2.4.2 可见性匹配原则

这里我的时间角度,就是说提交数据的那个事务(版本链中的事务),提交这个动作发生在什么时候

image-20240508231000827

首先,显而易见的几个条件是:

序号 条件 可见性 时间角度 描述
1 db_trx_id < min_trx_id 可见 过去 创建ReadView时,数据已经提交。
2 db_trx_id >= max_trx_id 不可见 未来 创建ReadView时,数据还位提交。
3 db_trx_id = creator_trx_id 可见 当前 就是当前事务,数据对当前事务可见。

对于min_trx_id <= db_trx_id < max_trx_id这个区间的数据,要结合m_ids来判断。

序号 条件 可见性 时间角度 描述
1 db_trx_idm_ids 不可见 未来 创建ReadView时,数据仍然活跃,还未提交。
2 db_trx_id 不在 m_ids 可见 过去 创建ReadView时,数据已经提交

2.4.3 判断检查结果

  • 如果数据版本对当前事务可见,则可以读取该数据版本。
  • 如果数据版本对当前事务不可见,则继续检查下一个版本,直到找到一个可见的版本或者版本链结束。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

软件测试学习之linux学习

今天是第三天,主要学了函数

Shell编程之条件语句

目录1.条件测试2.文件测试与整数测试(1)文件测试(2)整数测试3.字符串测试与逻辑测试(1)字符串测试(2)逻辑测试4.if语句(1)if单分支语句(2)if双分支语句(3)if多分支语句5.case分支语句 1.条件测试 Shell环境根据命令执行后的返回状态值($?)来判断是否执行成功,…

git merge指定提交(commit)

第一种 idea图形化界面操作 1.首先切换到要合并提交的分支上(即没有这些提交的分支) 2. 在git提交log里选有这些提交的分支,并将提交捡出 有多个提交的话就cherry pick多个提交就行,最后一起push 3. git push 下班记得打卡

麒麟 V10 一键安装 Oracle 11GR2(231017)单机版 2

https://www.modb.pro/db/1762008192972820480 安装准备1、安装好操作系统,建议安装图形化 2、配置好网络 3、挂载本地 ISO 镜像源 4、上传必须软件安装包(安装基础包,补丁包:33991024、35574075、35685663、6880880) 5、上传一键安装脚本:OracleShellInstall✨ 偷懒可以…

苯乙烯

反弹转空了。

《编译原理》阅读笔记:p1-p3

《编译原理》学习第 1 天,p1-p3总结,总计 3 页。 一、技术总结 1.compiler(编译器) p1, But, before a program can be run, it first must be translated into a form in which it can be executed by a computer. The software systems that do this translation are call…

c语言程序设计——实验报告七

实验项目名称:实验7数组的基本使用 实验项目类型:验证性 实验日期:2024年4月22日一、实验目的 1.熟练掌握数组的定义格式和数组元素的表示方法 2.熟悉数组的初始化方法和赋值方法 3.掌握字符数组存放字符串的方法和字符串函数的使用 4.熟悉数组元素的操作,特别是输入与输出…

[附源码]秦时明月6.2魔改版_搭建架设教程_附GM工具_安卓苹果

本教程仅限学习使用,禁止商用,一切后果与本人无关,此声明具有法律效应!!!! 教程是本人亲自搭建成功的,绝对是完整可运行的,踩过的坑都给你们填上了 一. 演示视频 https://githubs.xyz/boot?app=50二. 环境 联网环境: centos7.6 , 放开所有端口 单机环境: VM虚拟机…