手把手带你探索 MySQL 事务的隔离(下)

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

还有一点就是 MySQL 有一个参数设置值 autocommit,默认是 1 表示的是事务自动提交,每一个查询都是一个单独的事务自动提交,就像图中事务 C,update 就是一个单独的事务,更新完自己提交。当然你可以使用显式的 begin/commit。


让我们把目光对准上面的图,事务 B 的查询结果 K 是 3,事务 A 的查询结果 K 是 1,你是不是想骂我?你先别急着骂,让我们来看下结果。打开三个控制台。


1668577486260.jpg


好吧我没瞎说吧,现在你可以开始骂我了,你不是说在可重复读隔离的情况下,当前事务执行过程中看到的视图始终是启动时的视图嘛。


在 MySQL 中有两个视图概念:


一个是 view。也就是创建视图,语句是 create view xxx () as....., 它并不是一个真实的表,它的内容是由存储在数据库中进行查询操作的 SQL 语句定义的。


另一个就是 InnoDB 在实现 MVCC 是用到的一致性读视图 (consistent read view)。用于支持读已提交 RC (Read Committed) 和可重复读 RR (Repeatable Read) 的隔离级别实现。


InnoDB 每一个事物都存在一个事务唯一 ID,叫做 transaction id, 它是一个事务在启动的时候 InnoDB 向系统申请的,严格按照递增的形式生成。


每一行数据都有对应多个版本,每次通过事务更新的数据都会生成新的版本,然后把 transaction id 赋值给这个版本事务 ID,记为 row trx_id, 同时,为了之后可以恢复数据,我们需要保留旧的数据版本。也就是说在当前最新的版本中,我们可以随时获取旧的数据。下图对应修改一行数据的版本图。


1668577497405.jpg

                                     注:图片来源极客时间


从上图可以知道,最新版本是 V4, 且是由事务 transaction id =25 更新的,所以对应此行数据的数据版本 row trx_id =25。


按照可重复读的定义。一个事务启动的时候,可以看到所有已经提交的事务,但是接下来的事务对它来说是不可见的。所以对于一个事务启动的时候,如果一个事务在我启动时刻之前生成的,我就认,如果在我启动之后生成的,我就不认,我必须要找到它的上一个版本。有点渣男的嫌疑。如果上一个版本还不可见,那就继续往前面找,当然在这个过程中,自己更新的东西得认。


在实现上,InnoDB 为每一个事务创建了一个数组。事务中 ID 最小的称为低水位,当前系统中已经创建的事务 ID 最大值加 1 就是高水位。这个数组和水位图,就组成了当前事务的一致性图。数据版本可见性,就是基于数据版本数组和水位视图的比较而得到的结果。


这个视图数组把所有的 row trx_id 分为以下几种情况


1668577513037.jpg

                                       注:图片来源极客时间


如果当前事务启动的时候,一个数据版本 (row trx_id) 落在绿色部分,表示这个事务是已提交的版本或者是自己生成的,可见。


如果落在红色部分,说明这个版本是由将来启动的事务生成的,肯定不可见。


如果落在黄色,又分为两种情况。如果 row trx_id 存在数组中,说明, 此时版本数据还未提交事务,不可见,如果不在,说明已经提交事务了,可见。  


接下来可以分析为什么上面 A 查询的 k=1,B 查询的 k=3 了。


1668577537254.jpg


查看上图,我们假设当前有一个活跃的事务 99,目前我们更新的这一行数据的数据版本 row trx_id=90,此时系统存在 4 个事务,那么对于 A 的视图数组就是 [99,100],B 的视图数组就是 [99,100,101],C 的活跃数组就是 [99,100,101,102]。当前版本 101。


从图中知道,事务 A 先启动,接着事务 B,最后事务 C,但是第一个有效更新的是事务 C, 设置 k 为 2 (k=1+1), 然后是事务 B 把 k 设置为 3 (k=2+1), 接着到 A 查询了,他的视图数组是 [99,100], 此时数据版本 (1,3) 也就是 row trx_id=101 , 一对比,发现这货在高水位。不可见,再往回追,(1,2) 数据版本 row trx_id=102, 我去还是在高水位,不可见,最后追到 (1,1) 数据版本 row trx_id=90,比水位低,可见,一看上面的值 K=1, 所以查询结果就等于 1。


这样一个流程走下来,虽然中间修改了数据,数据版本也发生了变化,但是对于事务 A 来说,对他都是不可见的,所以看到的结果还是之前的数据。


到这里还有一个疑问,也就是开头的,事务 B 是在事务 C 之前开启事务的啊,对于事务 B 来说,事务 C 的操作对他来说是不可见的啊,事务 B 为什么获取的值是 2,然后再 2 的基础上更新了,它启动事务的时候 k 可不等于 2。


是的道理是没错,前提是如果事务 B 在更新之前先查询一遍数据,那么之后在它更新完数据以后,再次查询得到的值将会是 1, 而不是 3。这里运用到一条规则,更新数据的时候都是先读后写的。而这个读,只能读当前的值,叫做 "当前读"。对于 B 来说,在它更新之前,并没有执行读操作,所以在更新的时候,不能再在历史版本上直接更新了,否则 C 的更新将会丢失。所以 B 在更新的时候当前读 (1,2),更新之后 (1,3),当前的版本也就是 row trx_id=101 了。等到他查询的时候,一看当前版本号 101 就是自己,所以查询的时候就等于 3。


下面可以试验一下当 B 在更新之前查询一遍数据,然后更新数据再查询,符合上面所说的,得到的值就是 1。此时运用的就是当前读。


1668577547322.jpg


最后如果改动一下 C 事务中的执行,结果又是什么?\


1668577559057.jpg


这时候的事务 C 不再是自动提交事务,也是显式提交。事务 C' 更新语句,先获取写锁,但是 C' 事务还未提交,此时事务 B 是当前读,必须读取当前最新版本,而且必须加锁,等到 C 提交了,事务 B 才得以继续进行。那么 B 查询的结果不会变依然是之前的 3,而事务 C 的事务已经提交了,在读隔离的情况下,是在创建新视图之前,所以 A 的结果 k=2。


可重复读的核心就是一致性读。而事务更新数据的时候,只能用当前读,如果当前要读的记录的行数被其他事务占用的时候,就需要等待。


而读提交的逻辑和可重复读的逻辑类似,最主要的区别在于:


在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;


在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
2月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
124 43
|
25天前
|
关系型数据库 MySQL
mysql事务特性
原子性:一个事务内的操作统一成功或失败 一致性:事务前后的数据总量不变 隔离性:事务与事务之间相互不影响 持久性:事务一旦提交发生的改变不可逆
|
24天前
|
关系型数据库 MySQL 数据库
MySQL事务隔离级别及默认隔离级别的设置
在数据库系统中,事务隔离级别是一个关键的概念,它决定了事务在并发执行时如何相互隔离。MySQL提供了四种事务隔离级别,每种级别都解决了不同的并发问题。本文将详细介绍这些隔离级别以及MySQL的默认隔离级别。
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1698 14
|
3月前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
685 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
2月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
3月前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
168 4
MySQL基础:事务
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL】索引和事务
【MySQL】索引和事务
62 0
|
3月前
|
SQL Oracle 关系型数据库
详解 MySQL 的事务以及隔离级别
详解 MySQL 的事务以及隔离级别
52 0

推荐镜像

更多
下一篇
DataWorks