IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> MySQL事务并发问题和MVCC机制 -> 正文阅读

[大数据]MySQL事务并发问题和MVCC机制

MySQL事务并发问题和MVCC机制

事务并发的几种问题

1.脏读(读未提交数据)

  • 脏读指的是事务读取到其他事务没有提交的数据
  • 举个栗子
    在这里插入图片描述

事务A读取表中的name,事务B将表中的张三修改称为了张老三,假设这时候事务A读取到了name为张老三,但是到最后事务B又因为其他原因回滚了数据,数据库表中的name为张三,那这就出现了问题,事务A读到的数据和数据库表中的不一致.而且这个数据变化到底是因为原因造成的事务A是不知道的

2.不可重复读(并发更新的情况下)

  • 不可重复读指的是在同一次事务中前后查询不一致的问题
  • 举个栗子
    在这里插入图片描述

事务A先查询了数据库中的人员名字,之后就去处理其他的数据,之后有重复了最开始查询的内容,那么事务A预期的应该是两次查询的结果应该是一致的,因为事务A在处理其他数据的时候,没有对查询的数据做一个修改
但是问题是在事务A处理其他数据的时候,事务B对事务A查询的数据做了更新且提交了,那么事务A和事务B在并发的情况下,两次查询的结果就不一致了
但是实际的理论上我们事务A没有对数据进行更新,那么在事务A在没有提交之前,无论查询多少次数据都应该是一致的才对,这个理论情况叫做可重复的
上面并发出现的这个情况叫做不可重复读
同一个事务前后两次读取的数据不一致,就导致我们的程序不可预期不可控,这也就是不可重复读带来的危害

3.幻读(并发新增,删除这种导致数据总量发生变化的操作)

  • 幻读是一次失误当中前后数据量发生变化,用户产生不可预估的问题
  • 举个栗子在这里插入图片描述

在这个例子当中,事务A先查询了数据库表发现有一条数据,他在删除了这个数据之后,事务B向数据库表当中插入了一条数据,事务A此时还没有提交,当事务A再次查询数据库表的收,预期结果应该是空数据,但是凭空多出来这个李四是什么鬼,这个就是这两个事务在并发情况下发生的幻读问题

事务隔离级别

在这里插入图片描述

其中MySQL默认的事务隔离级别是第三个:可重复读,比较特殊的要记住就是,常常说可重复读事务隔离级别能避免脏读和不可重复读,但是不能避免幻读,但是实际上如果我们的数据库使用的是InnoDB存储引擎是不存在幻读的.

获取和设置事务隔离级别的命令

  • 其实一般不用设置,使用默认的就行,因为MySQL5.1之后默认使用的是InnoDB存储引擎,且默认的事务隔离级别是RR,能够避免三种并发事务问题
    在这里插入图片描述
  • 为啥InnoDB存储引擎在RR事务隔离级别下也能够避免幻读呢?这就要说说这个MVCC机制了

MVCC机制

写在前面

在MySQL的InnoDB存储引擎下 RC和RR 事务隔离级别都是基于这个MVCC(多版本并发控制)进行并发事务的控制的
然后这个MVCC是基于这个"数据版本"对并发事务进行访问的

示例分析

在这里插入图片描述

有四个事务ABCD其中前三个事务执行的操作都是对表中name字段进行修改
事务D执行的操作是进行数据的查询,但是仔细看事务D查询的位置还特殊的不行,第一次查询是在事务A提交之后事务B提交之前,第二次查询数据是在事务B提交之后在事务C提交之前

  • 分别在RR隔离级别和RC隔离级别下分析下两次查询读取到的数据情况
    RR隔离级别下

RR隔离级别是可重复读,那么就意味着在整个事务中读取到的数据是一致的那么显而易见第一次查询和第二次查询得到的数据是一致的,即name=张三

RC隔离级别下

由于RC是读已提交,只要别的事务提交数据,我就进行读取,那么实际上最后RC隔离级别下两次读到的数据分别是: 第一次:张三 第二次:张小三
显而易见RC隔离级别下出现的问题就是不可重复读

分析现象

基于UNDO_LOG的版本链
  • UNDO_LOG是回滚日志,在我们进行事务处理的时候,只有增加回滚日志,当我们事务执行失败的时候要执行rollback回滚操作的时候才能够进行还原.其原理就是采用了链的方式进行组织.
    在这里插入图片描述
  • 最上面一行的数据就是我们数据库中该字段当前的数据,并且当时执行这个事务update语句的事务编号为TRX_ID = 3
  • 额外附加的字段1:TRX_ID执行这个版本的数据是哪个事务执行的结果,就记录下这个事务的id
  • 额外添加字段2:DB_ROLL_PTR:指针信息,指向了上一次进行版本变化的时候他的数据是什么
  • 按照这个表我们就可以清楚的知道最原始的表中的数据是张三丰(假设),然后经过三次的更新之后更新为了张老三,每个数据都采用事务ID作为版本来进行标识
  • UNDO_LOG如果被删除了怎么办?中间数据被删除了UNDO_LOG版本链不就断了吗?

UNDO_LOG版本链不是立即删除的,MySQL确保版本数据链不再被引用之后在进行删除,所以除了一些不可控的因素之外,一般数据都是比较完整的

ReadView

  • ReadView是"快照读"SQL执行时MVCC提取数据的依据
  • 所以说使用MVCC机制的前提时快照读,这也是InnoDB存储引擎下RR事务隔离级别的一种实现方式
  • 如果读取方式不是快照读而是当前读,那么实现的机制就不是MVCC机制了而是使用了加锁的方式,加的是行锁和间隙锁
快照读和当前读
  • 快照读:就是最普通的select查询SQL语句就是快照读
  • 当前读:当指代执行下列语句时进行数据读取的方式:
insert into ...
update ...
delete ...
select ... for update
# 对当前增加了写锁
select ...lock in share mode
ReadView数据结构
  • ReadView就是一个数据接结构,它包含了4个字段
    在这里插入图片描述
读已提交(RC)场景下

在每一次执行快照读的时候生成全新的ReadView
在这里插入图片描述

  • 第一次快照读生成的readview从图中可以看出事务2,3,4还没有提交所以当前活跃事务id:m_ids={2,3,4},最小活跃事务id:min_trx_id=2,预分配事务id:max_trx_id = 5 (因为时当前最大活跃事务id + 1所以就是4 + 1 = 5),当前事务创建者id:creator_trx_id = 4
  • 第二次快照读生成的readview和第一次分析逻辑相同
版本链数据访问规则

版本链数据访问规则:

  1. 判断当前事务id等于creator_trx_id(4)吗?成立说明数据就是自己这个事务更改的,可以访问.
  2. 判断trx_id < min_trx_id(2) ? 成立则说明数据已经提交了,可以访问.
  3. 判断trx_id > max_trx_id(5) ? 成立则说明该事务是在readview生成以后才开启的,不允许访问.
  4. 判断min_trx_id(2) <= trx_id <= max_trx_id(5),成立在m_ids数据中进行对比,不存在则代表数据是已经提交的,可以进行访问.
    让undo_log版本链中的版本从小到校一次带入到这个规则当中进行判断找到第一个可以访问的数据.
  • 第一次生成的readview

在这里插入图片描述
这个快照读带入可以在trx_id = 1这个版本的时候,满足trx_id < min_trx_id(2) 说明数据已经提交可以访问所以第一次查询语句查询出来的数据就是张三.

  • 第二次生成的快照读

在这里插入图片描述
这个快照读可以在trx_id = 2的时候满足规则中的第二条 trx_id < min_trx_id(3)说明数据已经提交了,读取的数据为张小三 !!!出现了不可重复读的现象

可重复读(RR)的场景
  • 仅在第一次执行快照读时生成ReadView,后续快照读复用这个ReadView(但是存在例外)
    在这里插入图片描述
  • 那么在这样的情况下,版本链不变化,ReadView不变,那么两次读的结果肯定是一样的
  • RR级别下使用MVCC能避免幻读吗? 能但是不完全能!

连续多次快照读的时候,ReadView会产生复用,没有幻读问题
但是需要注意的是:当两次快照读之间存在当前读,ReadView会重新生成,导致产生幻读

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-06-29 19:08:56  更:2022-06-29 19:09:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 20:01:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码