可重复读实现原理

article/2025/9/28 11:43:03

不可重复读:事务A多次读取同一个数据,事务B在事务A多次读取的过程中,对数据作了更新,导致事务A多次读取同一个数据时,结果不一致。(比如修改行数据)
幻读:事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据 称为幻读。(比如查询表中数据记录数)

浅解释

概念
1、InnoDB 在每行记录后面保存两个隐藏的列,分别保存了数据行的创建版本号和删除版本号。每开始一个新的事务,系统版本号都会递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的创建版本号对比。
2、insert:为插入的每一行保存当前系统版本号作为创建版本号。
3、delete:为删除的每一行保存当前系统版本号作为删除版本号。
4、update:插入一条新数据,保存当前系统版本号作为创建版本号。同时保存当前系统版本号作为原来的数据行删除版本号。
演示

事务A插入一条数据,假设当前系统版本号为1
insert into user (id,name) values (1,'Tom');
得到这条数据
id      nanme       create_version        delete_version1       Tom                1      事务A查询数据---根据事务A版本号
select * from user where id = 1;
得到这条数据
id      nanme       create_version        delete_version1       Tom                1      事务B修改数据,事务B版本号为2
update user set name = 'Jerry' where id = 1;
提交后
id      nanme       create_version        delete_version1       Tom                1                    2    1       Jerry              2                     事务A查询数据---根据事务A版本号
select * from user where id = 1;
id      nanme       create_version        delete_version1       Tom                1                    2
**得出结论:可重复读并不会发生不可重复读**事务C删除数据
delete from user where id = 1;
id      nanme       create_version        delete_version1       Jerry              2                    3**得出结论:只有新增和修改会修改数据行的创建版本号、删除和修改会修改数据行的删除版本号**        

深解释

必知一
实际上,InnoDB 会在每行记录后面增加三个隐藏字段:
DB_ROW_ID:行ID,随着插入新行而单调递增,如果有主键,则不会包含该列。
DB_TRX_ID:记录插入或更新该行的事务的事务ID。
DB_ROLL_PTR:回滚指针,指向 undo log 记录。每次对某条记录进行改动时,该列会存一个指针,可以通过这个指针找到该记录修改前的信息 。当某条记录被多次修改时,该行记录会存在多个版本,通过DB_ROLL_PTR 链接形成一个类似版本链的概念。
必知二
每开启一个事务时,系统会给该事务会分配一个事务 Id,事务 A 开启事务的时候会生成一个 事务快照ReadView,主要包含以下几个属性
1、m_ids,当前有哪些事务正在执行,且还没有提交,这些事务的 id 就会存在这里;
2、min_trx_id,是指 m_ids 里最小的值
3、max_trx_id,是指下一个要生成的事务 id。下一个要生成的事务 id 肯定比现在所有事务的 id 都大;
4、creator_trx_id,每开启一个事务都会生成一个 ReadView,而 creator_trx_id 就是这个开启的事务的 id。
必知三
有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:
1)如果被访问版本的trx_id与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
2)如果被访问版本的trx_id小于ReadView中的up_limit_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
3)如果被访问版本的trx_id大于ReadView中的low_limit_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
4)如果被访问版本的trx_id属性值在ReadView的up_limit_id和low_limit_id之间,那就需要判断一下trx_id属性值是不是在trx_ids列表中。如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。

实现1:自己理解的
不好意思,这个图片转正不过来
在这里插入图片描述

实现2:他人博客讲的
1、事务是可以并发执行的,现在有事务 A、事务 B 这两个事务,且这两个都没有提交。事务 A 将会执行多次读操作,来模拟可重复读中多次读取同一行数据的场景。事务 B 则会修改这一行数据
在这里插入图片描述

2、事务 A 开启事务的时候会生成一个 ReadView,所以说这个 ReadView 的创建者就是事务 A,事务 A 的事务 id 是 10,所以 creator_trx_id 就是 10。

此时,总共就只有事务 A、事务 B 这两个事务,而且它们都还没有提交,所以说 m_ids 会把这两个事务 id,10、18 都记录下来。min_trx_id 是 m_ids 里面的最小值,10、18 中最小的显然是 10。当前最大的事务 id 是 18,那么下一个事务的 id 就是 19,max_trx_id 就是 19。

ReadView 生成之后,事务 A 就要去 undo log 版本链中读取值了。

现在只有一条 undo log 日志,但这并不意味着事务 A 就能读到这条日志的值 X。它要先判断这行日志的 trx_id 是否小于当前事务的 min_trx_id。看图我们可以很轻松地发现,日志的 trx_id = 8 小于 ReadView 中 min_trx_id = 10。

这就意味着,这个事务 A 开始执行之前,修改这行数据的事务已经提交了,所以事务 A 是可以查到值 X 的。
3、我们继续看,事务 A 第一次读完之后,事务 B 要修改这行数据了。undo log 会为所有写操作生成日志,所以就会生成一条 undo log 日志,并且它的 roll_pointer 会指向上一条 undo log 日志
在这里插入图片描述

4、紧接着,事务 A 第二次去读这行数据了,情况如下图所示:
在这里插入图片描述

第一次读的时候,开启事务 A 的时候就生成了一个 ReadView,R

此时事务 A 第二次去查询的时候,先查到的是 trx_id = 18 的那条数据,它会发现 18 比最小的事务编号 10 大。那就说明事务编号为 18 的事务,有可能它是读不到的。

​接着就要去 m_ids 里确认是否有 18 这条数据了。发现有 18,那就说明在事务 A 开启事务的时候,这个事务是没有提交的,它修改的数据就不应该被读到。

事务 A 就会顺着 roll_pointer 指针继续往下找,找到了 trx_id = 8 这条日志,发现这条能读,读到的值任然是 x,与第一次读到的结果一致。

成功实现可重复读!


http://chatgpt.dhexx.cn/article/Pn1cmHDB.shtml

相关文章

mysql “可重复读“ 解决了哪些问题,没有解决哪些问题?

可重复读解决了更新带来的不可重复读问题,但是没有解决插入或者删除带来的幻读问题。这句话,是老八股文了。 但真实情况是这样的吗?这个验证不麻烦,我们可以动手来验证一下。 我使用的是免安装版本的windows mysql8.0.31&#xff…

透彻解读mysql的可重复读、幻读及实现原理

目录 一、事务的隔离级别 二、mysql怎么实现的可重复读 举例说明MVCC的实现 MVCC逻辑流程-插入 MVCC逻辑流程-删除 MVCC逻辑流程-修改 MVCC逻辑流程-查询 三、幻读 快照读和当前读 四、如何解决幻读 事务隔离级别有四种,mysql默认使用的是可重复读&#x…

前端开发:a标签实现下载功能

应用背景 前端项目实现下载文件的功能,在后台没给我们撸接口的情况下,我们可以利用a标签实现下载功能,而且贼简单~ 实现原理 通过a标签的download的属性,将需要下载的文件放在前端项目中,然后href属性访问文件路径&a…

a标签/js下载文件(2020)

a标签/js 下载服务器文件 一、二进制式下载1、responseType(请求)2、Content-Type(响应)判断是普通数据还是文件流(可选)3、Content-Disposition(响应)和文件名(可选&…

a标签下载pdf文件

通过a标签的download属性可以实现下载pdf文件,不过有一个弊端:网站和pdf文件必须在同一域名下才可行,不然就是先打开一个新标签预览,然后点击下载按钮进行下载。

a标签实现文件下载功能

文件下载原理: java后台只能做到返回二进制流或文件给前端,最终在前端页面创建一个a,然后触发a的点击事件实现点击下载效果。 1.无需token的 2.请求头需要token 接口: 点击事件:

前端-基于a标签实现下载功能

最近在一个项目中需要实现下载功能,在前期与后端多次联调尝试使用接口下载文件无果后,最后抱着试一试的心态使用了A标签下载,方法是有效的,但是有部分局限性!!! 使用a标签实现下载的步骤如下&am…

a标签的download属性(荐)

在html 中 a 链接有 download 这样一个属性 它有什么用呢?! 我们在页面中提供下载的时候,都需要去配置一些服务端的东西,比如指定 zip 文件就通知浏览器下载这个文件。 但是,比如 .jpg 这样的图片文件,如…

html a标签下载文件

<a href"/user/test/xxxx.txt" download"文件名.txt">点击下载</a>

前端a标签实现文件下载

a标签实现文件下载 如果想通过纯前端技术实现文件下载&#xff0c; 下载的静态文件放项目路径下&#xff0c;A标签下载&#xff0c;herf指定项目路径&#xff0c;加上download属性。a链接默认的是在同一页面打开&#xff0c;如果我们需要打开新的页面&#xff0c;就需要添加t…

html利用a标签实现下载本地的文件

在写html页面的时候&#xff0c;需要在网页上提供一个下载按钮可以下载我自己电脑中的文件。我已经知道了该文件的路径&#xff0c;但是之前看了很多文章都没找到正确办法&#xff0c;一直不知道如何能够下载本地的文件&#xff0c;经过不断实验发现&#xff0c;可以利用a标签中…

一、<a>标签如何实现下载

实习期间负责的第一个项目&#xff1a;广东互联网协会官网。其中有一个很常见的功能----点击下载。 页面截图 在此之前&#xff0c;我所认识的<a>标签只是用于页面跳转的&#xff0c;实现文件下载是如何做到的呢&#xff1f; 答案是&#xff1a;使用href与download属性 …

面试官:如何用a标签实现文件下载?(一文带你手撕知识点)

前言 大家好&#xff0c;今天给大家带来前端小知识&#xff1a;前端利用a标签实现文件&#xff08;图片&#xff09;下载&#xff0c;也就是教大家利用a标签或者是 window.open() 来实现下载功能。 文章目录 前言常用方式方法分析代码实现 常用方式 <a href"url"…

Jquery之遍历元素

J q u e r y Jquery Jquery之遍历元素 使用 e a c h ( ) each() each()方法传入函数两个参数分别为 i n d e x , d o m index,dom index,dom对象。 <body><div>1</div><div>2</div><div>3</div> </body> <script src&quo…

jQuery 遍历数据

在jQuery 中&#xff0c; $.each( )方法主要用于遍历数据&#xff0c;通过该方法&#xff0c;我们可以遍历任何一个对象&#xff0c;比如数组和对象。 语法格式&#xff1a; $.each(object,function(index,ele))示例&#xff1a; &#xff08;1&#xff09;遍历数组的数据 …

jQuery - 元素遍历

前言&#xff1a; 一提到“遍历”,大家一般都能联想到 each() 或者 for()等语法&#xff0c;但是在jQuery中究竟什么是遍历&#xff1f; 什么是遍历&#xff1a; jQuery 遍历&#xff0c;意为"移动"&#xff0c;用于根据其相对于其他元素的关系来"查找&qu…

Jquery-节点遍历4种方法

节点遍历 遍历子元素 遍历同辈元素 遍历前辈元素 其他遍历方法 遍历子元素 children()方法可以用来获取元素的所有子元素 $(selector).children([expr]); 获取<section>的子元素&#xff0c;但不包含子元素的子元素 var $section $("section").childr…

jq遍历元素

jq遍历元素 通过jq遍历元素、并控制一些元素的属性&#xff08;显示/隐藏、value、src等等&#xff09;&#xff0c;是我们在开发之中比较常见的操作&#xff0c;也为我们的业务功能扩宽了方向&#xff0c;接下来我将结合近段时间在工作上的际遇粗略介绍一下一些稍稍复杂的jq遍…

JS 遍历

目录 1. for 数组遍历2. for ... of3. forEach( )4. some( )5. every( )6. filter( )7. map( )8. find( )9. findIndex( )10. reduce( )11. reduceRight( ) 对象遍历1. for ... in2. Object.keys( )3. Object.values( )4. Object.entries( )5. Object.getOwnPropertyNames( ) 1…

数据库——数据字典

数据库——数据字典是什么&#xff1f; 一.数据字典以及使用场景&#xff1a; User表&#xff0c;User主体有很多属性&#xff0c;比如证件&#xff08;身份证、居住证、港澳通行证…&#xff09;地区&#xff08;河北、河南、北京…&#xff09;等&#xff0c;然后表建好了&…