“时光机”与“多维视界”⭐️MySQL中原子性与隔离性的科幻大片

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: “时光机”与“多维视界”⭐️MySQL中原子性与隔离性的科幻大片

“时光机”与“多维视界”⭐️MySQL中原子性与隔离性的科幻大片

上篇文章 我们描述完MySQL的持久性等知识点,本篇文章来描述MySQL的原子性与隔离性知识

”时光机“指的是实现原子性的undo log,”多维视界“指的是实现并发场景下读不加锁的MVCC,一起往下看看吧~

内容脑图如下:

image.png

MySQL中支持事务的只有Innodb,因此本篇文章描述的原理也是Innodb实现原子性的原理

事务的原子性:一组事务要么都成功,要么都失败

在事务中可能存在一些写操作(新增/修改/删除),有的写操作会执行成功,但是后续写操作执行失败就会导致事务需要回滚,那么执行成功的写操作就要退回到原来的“版本”

为了方便回滚,Innodb使用undo log来记录每次写操作修改的内容,根据undo log能够快速退回到原始版本

每一行记录中存在隐藏列 roll_pointer 回滚指针,它指向上一次写操作产生的undo log,undo log中也存在类似回滚指针的列,它能够找到它上一次写操作产生的undo log

image.png

记录与undo log就会形成一条”版本链“,这样在遇到回滚时便能快速的回到原来的版本以此来实现原子性(回滚)

image.png

注意:undo log只是记录修改的数据,并不是完整数据,图中只是为了方便展示,图中执行SQL顺序为从下到上

隔离性

为了防止并发事务交叉执行导致的数据不一致等并发问题,MySQL会根据不同的隔离级别来解决不同的隔离性问题

隔离性问题与隔离级别

不同隔离级别下会使用不同的方案来达到隔离性,我们先来复习一下隔离性问题和隔离级别:

隔离性问题

脏写:A事务和B事务同时修改一行记录,A可以覆盖B修改后未提交的记录,后续B又进行回滚

脏读:A事务读取B事务未提交的记录,然后B事务回滚,导致A事务读取的数据不一致

不可重复读:A事务前后两次执行同一个查询,返回的结果数据不同,B事务在此期间进行修改

幻读:A事务前后两次执行同一个查询,返回的结果数量不同,B事务在此期间进行新增

幻读强调结果数量不同,不可重复读强调结果数据不同

隔离级别

读未提交(RU):可以读到其他事务未提交的记录,会出现脏读、不可重复读、幻读

读已提交(RC):只能读到其他事务提交的记录,会出现不可重复读、幻读

可重复读(RR):Innodb默认,不会出现不可重读的情况,可能出现部分幻读

串行化(S):所有隔离性问题都会不发生

随着隔离性的严格,性能也会降低:RU > RC > RR > S

MVCC

那么在undo log的版本链中是如何做到有的事务能够看到该版本、有的事务看不到该版本的呢?

其实这是通过MVCC(Multi Version Concurrency Control 多版本并发控制)来实现的,MVCC在这种读写并发的场景下,使用无锁机制读取到满足隔离级别的数据

对于事务来说,当事务中出现第一条写操作的语句时就会生成事务ID,这个事务ID是全局递增的

当使用MVCC时会生成read view来判断当前事务能够读到哪个版本上的记录

read view中就包含事务ID相关的属性,便于判断事务能读到哪个版本

  1. 最小事务ID:read view生成时活跃事务中最小的id
  2. 最大事务ID:read view生成时活跃事务中最大的id
  3. 活跃事务列表:read view生成时存在的活跃事务

image.png

前面说到:事务ID是全局自增的,这表示可以根据事务ID查看哪个事务先执行、哪个事务后执行、哪个事务已提交/回滚、哪个事务当前还在执行中

使用read view与版本链上的最新记录进行判断(判断规则如下):

  1. 如果read view的最小事务id大于该记录的事务id,说明该记录的事务已经提交了,那么是可以查看的
  2. 如果read view的最大事务id小于该记录的事务id,说明该记录的事务在当前事务开启后才开始,那么无法查看
  3. 如果该记录id在read view最小、大事务id之间,那么要查看当前活跃事务列表,如果在列表中,说明该列的事务活跃(还未结束),则无法查看;反之则可以查看
  4. 如果记录的事务id是当前事务,则可以查询(当前事务执行的,当然可以查看)

当该版本的记录无法查看时,就会遍历版本链继续向下一条记录使用该规则

比如read view 最小事务id:20 最大事务id:30 活跃事务列表:20,22,24,27,30

当记录的事务id为19时,小于最小事务id,说明它已经提交可以查看

当记录的事务id为31时,说明生成read view时,它还没开启事务,不能查看

当记录的事务id为24时,在最小19、最大30之间,要查看活跃事务列表中是否存在,存在则不能查看

当记录的事务id为23时,活跃事务列表中不存在则可以查看

分析读相关解决隔离性问题的方案

在了解隔离性问题与隔离级别后,我们来进行一一分析:

脏写发生在写写的场景下会破坏数据的一致性,禁止这种情况发生,会使用行锁保证(锁相关知识下篇文章再说)

脏读发生在读写的场景下会读的数据不一致,也要禁止这种情况发生,正常情况读写场景下需要保证数据一致性的办法就是加行锁互相阻塞

RC使用MVCC机制,在进行读操作时使用read view查看版本链上的记录是否可读,如果事务已提交(事务id会比read view最小事务id要小),以此通过无锁机制达到防止脏读的效果

不可重复读侧重的是有其他事务在本次事务多次查询过程中修改这个数据的内容(幻读侧重数量)

RC下,由于每次读都生成read view,前后两次读生成的read view不同,能看到的数据也就可能不同

RR使用MVCC机制,在同个事务中只有第一次读生成read view,后续读都使用这个read view,以此来达到防止不可重复读,和大部分幻读

幻读案例

为啥说RR可以防止大部分幻读呢?

RR通过read view可以看到的数据是不变的,因此可以防止幻读

那为啥说是防止大部分幻读而不是所有幻读呢?

还记得第四条规则(如果记录的事务id是当前事务,则可以查询)吗?

在某些场景下就会导致特殊幻读,来看一个案例:

时间点 T1 T2
1 begin;
SELECT * FROM s where id < 30;
2 insert into s (id,s_name,s_age) value (18,'caicai',18);
3 update s set s_name = '菜菜的后端私房菜' where id = 18;
4 SELECT * FROM s where id < 30;
commit;

T1 先进行查询(-∞,30),T2在该区间插入一条记录(18),如果此时再进行读则数据还是一致的

但是T1对这条新增的记录进行修改,导致T1的read view对该事务可见,从而导致第二次读到这条T2新增的数据发生幻读

在S串行化下,如果是自动提交则只有一条读会使用mvcc,写则会加锁

至此,我们描述完读相关解决不同隔离性的方案,写相关解决不同隔离性的方案与锁相关,我把它放在下一篇文章和锁一起进行讲解

总结

记录的隐藏列中存在回滚指针和事务ID,回滚指针指向undo log,undo log又可以通过指针找到上一次修改产生的undo log,从而形成版本链(undo log只记录修改数据)

事务的原子性(需要回滚时)可以通过undo log实现

在并发读写场景下,Innodb的读操作通过mvcc来保证不同隔离性下数据一致性

mvcc使用生成read view、全局递增的事务ID和能够看到哪个版本的校验规则来实现

RU读时没使用mvcc,可以直接读到版本最新记录

RC每次读时生成read view,只能防止脏读

RR第一次读生成read view,可以防止脏读、不可重复读、大部分幻读

S只在自动提交时使用mvcc

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 MySQL进阶之路,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 gitee-StudyJavagithub-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
1
1
0
64
分享
相关文章
确保数据完整性:探究MySQL中的原子性特性
在数据库管理中,"原子性"是一个至关重要的概念,对于维护数据的一致性和可靠性具有关键作用。在本文中,我们将深入探讨MySQL中的原子性特性,解释其含义、重要性以及如何保障数据的原子性操作。
677 0
太实用了!JSON在Mysql中原来可以这么玩
太实用了!JSON在Mysql中原来可以这么玩
433 0
跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现
跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现
309 0
跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
185 1
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
大数据新视界 --面向数据分析师的大数据大厂之 MySQL 基础秘籍:轻松创建数据库与表,踏入大数据殿堂
本文详细介绍了在 MySQL 中创建数据库和表的方法。包括安装 MySQL、用命令行和图形化工具创建数据库、选择数据库、创建表(含数据类型介绍与选择建议、案例分析、最佳实践与注意事项)以及查看数据库和表的内容。文章专业、严谨且具可操作性,对数据管理有实际帮助。
大数据新视界 --面向数据分析师的大数据大厂之 MySQL 基础秘籍:轻松创建数据库与表,踏入大数据殿堂
MySQL下载安装全攻略!小白也能轻松上手,从此数据库不再难搞!
这是一份详细的MySQL安装与配置教程,适合初学者快速上手。内容涵盖从下载到安装的每一步操作,包括选择版本、设置路径、配置端口及密码等。同时提供基础操作指南,如数据库管理、数据表增删改查、用户权限设置等。还介绍了备份恢复、图形化工具使用和性能优化技巧,帮助用户全面掌握MySQL的使用方法。附带常见问题解决方法,保姆级教学让你无忧入门!
MySQL下载安装全攻略!小白也能轻松上手,从此数据库不再难搞!
docker拉取MySQL后数据库连接失败解决方案
通过以上方法,可以解决Docker中拉取MySQL镜像后数据库连接失败的常见问题。关键步骤包括确保容器正确启动、配置正确的环境变量、合理设置网络和权限,以及检查主机防火墙设置等。通过逐步排查,可以快速定位并解决连接问题,确保MySQL服务的正常使用。
665 82

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问