MySQL怎样实现可重复读写?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

简单理解一下可重复读

可重复读是指:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。

我们可以简单理解为:在可重复读隔离级别下,事务在启动的时候就”拍了个快照“。注意,这个快照是基于整个库的。

这时,你可能就会想,如果一个库有 100G,那么我启动一个事务,MySQL就要拷贝 100G 的数据出来,这个过程得多慢啊。可是,我平时的事务执行起来很快啊。

实际上,我们并不需要拷贝出这 100G 的数据。我们来看下”快照“是怎么实现的。

申请阿里云服务时,可以使用2000元阿里云代金券,阿里云官网领取网址:https://dashi.aliyun.com/site/yun/youhui

拍个快照

InnoDB 里面每个事务都有一个唯一的事务 ID,叫作 transaction id。它在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

每条记录在更新的时候都会同时记录一条 undo log,这条 log 就会记录上当前事务的 transaction id,记为 row trx_id。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

如下图所示,一行记录被多个事务更新之后,最新值为 k=22。假设事务A在 trx_id=15 这个事务提交后启动,事务A 要读取该行时,就通过 undo log,计算出该事务启动瞬间该行的值为 k=10。

_k_10_jpeg

在可重复读隔离级别下,一个事务在启动时,InnoDB 会为事务构造一个数组,用来保存这个事务启动瞬间,当前正在”活跃“的所有事务ID。”活跃“指的是,启动了但还没提交。

阿里云服务器1核2G低至82元/年,阿里云官活动网址:https://dashi.aliyun.com/site/yun/aliyun 可以用20代金券,即102-20=82。

数组里面事务 ID 为最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。

这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。

这个视图数组把所有的 row trx_id 分成了几种不同的情况。

几种不同的情况

如果 trx_id 小于低水位,表示这个版本在事务启动前已经提交,可见;

如果 trx_id 大于高水为,表示这个版本在事务启动后生成,不可见;
如果 trx_id 大于低水位,小于高水位,分为两种情况:
若 trx_id 在数组中,表示这个版本在事务启动时还未提交,不可见;
若 trx_id 不在数组中,表示这个版本在事务启动时已经提交,可见。
InnoDB 就是利用 undo log 和 trx_id 的配合,实现了事务启动瞬间”秒级创建快照“的能力。

举个栗子

初始化语句

_jpeg

下表为事务A, B, C 的执行流程
C_jpeg

我们假设事务A, B, C 的 trx_id 分别为 100, 101, 102。事务A开始前活跃的事务 ID 只有 99,并且 id=1 这一行数据的 trx_id=90。
根据假设,我们得出事务启动瞬间的视图数组:事务A:[99, 100],事务B:[99, 100, 101],事务C:[99, 100, 101, 102]。
99_100_101_102_jpeg

事务C通过更新语句,把 k 更新为 2,此时trx_id=102;
事务B通过更新语句,把 k 更新为 3,此时trx_id=101;
事务B通过查询语句,查询到最新一条记录为3,trx_id=101,满足隔离条件,返回 k=3;
事务A通过查询语句:
1.查询到最新一条记录为3,trx_id=101,比高水位大,不可见;
2.通过 undo log,找到上一个历史版本,trx_id=102,比高水位大,不可见;
3.继续找上一个历史版本,trx_id=90,比低水位小,可见。

提出问题:为啥事务B更新的时候能看到事务C的修改?

我们假设事务B在更新的看不到事务C的修改,是什么个情况?

事务B查询到最新一条记录为2,trx_id=102,比高水位大,不可见;
通过 undo log,找到上一个版本,trx_id=90,比低水位小,可见;
返回记录 k=1,执行 k=k+1,把 k 更新为2,此时 trx_id=101。
如果是这种情况,事务C可能就蒙了:“啥子情况,我的更新怎么就丢了”。事务B覆盖了事务C的更新。

所以,InnoDB在更新时运用一条规则:更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读“ (current read)。

因此,事务B在更新时要拿到最新的数据,在此基础上做更新。紧接着,事务B在读取的时候,查询到最新的记录为3, trx_id=101 为当前事务ID,可见。

我们再假设另一种情况:

事务B在更新之后,事务C紧接着更新,事务B回滚了,事务C成功提交。
_C_jpeg

如果按照当前读的定义,会发生以下事故,假设当前 K=1:

事务B把 k 更新为 2;
事务C读取到当前最新值,k=2,更新为3;
事务B回滚;
事务C提交。
这时候,事务C发现自己想要执行的是 +1 操作,结果变成了 ”+2“ 操作。

InnoDB 肯定不允许这种情况的发生,事务B在执行更新语句时,会给该行加上行锁,直到事务B结束,才会释放这个锁。
_jpeg

小结

InnoDB 的行数据有多个版本,每个版本都有 row trx_id。事务根据 undo log 和 trx_id 构建出满足当前隔离级别的一致性视图。可重复读的核心是一致性读,而事务更新数据的时候,只能使用当前读,如果当前记录的行锁被其他事务占用,就需要进入锁等待。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
14天前
|
JavaScript 关系型数据库 MySQL
关于 MySQL 重复读导致的重复插入问题
本文介绍了在开发业务接口时遇到的MySQL重复读导致的数据重复插入问题,并通过伪代码示例详细解析了问题产生的原因。文章提出了四种解决方案:使用共享锁、控制事务并发执行、强制当前读以及调整隔离级别为READ COMMITTED,旨在确保读取最新数据,避免数据重复插入。
|
6月前
|
关系型数据库 MySQL
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
【mysql技巧】如何在这个mysql语句执行前加个前提,也就是只有表里没有相同数据才进行添加插入操作
40 1
|
2月前
|
存储 关系型数据库 MySQL
面试官:MySQL一次到底插入多少条数据合适啊?
本文探讨了数据库插入操作的基础知识、批量插入的优势与挑战,以及如何确定合适的插入数据量。通过面试对话的形式,详细解析了单条插入与批量插入的区别,磁盘I/O、内存使用、事务大小和锁策略等关键因素。最后,结合MyBatis框架,提供了实际应用中的批量插入策略和优化建议。希望读者不仅能掌握技术细节,还能理解背后的原理,从而更好地优化数据库性能。
|
3月前
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
412 6
|
SQL 数据可视化 关系型数据库
【MySql】MySQL排序分页查询数据顺序错乱的原因和解决办法
【MySql】MySQL排序分页查询数据顺序错乱的原因和解决办法
632 0
|
SQL 关系型数据库 MySQL
MySQL防止重复插入(数据库层where方法解决)
MySQL防止重复插入(数据库层where方法解决)
38 0
|
存储 关系型数据库 MySQL
MySQL中的索引事务(1)索引----》数据库运行的原理知识+面试题~
MySQL中的索引事务(1)索引----》数据库运行的原理知识+面试题~
52 0
|
SQL 关系型数据库 MySQL
MySQL中的索引事务(2)事务----》数据库运行的原理知识+面试题~
MySQL中的索引事务(2)事务----》数据库运行的原理知识+面试题~
64 0
|
SQL 存储 缓存
MySQL日志顺序读写及数据文件随机读写原理
MySQL在实际工作时候的两种数据读写机制: 对redo log、binlog这种日志进行的磁盘顺序读写 对表空间的磁盘文件里的数据页进行的磁盘随机读写
230 0
|
关系型数据库 MySQL 数据库管理
解决 MySQL 分页数据错乱重复
解决 MySQL 分页数据错乱重复
248 0