事务到底是隔离还是不隔离?

news/2024/5/5 7:46:56/文章来源:https://blog.csdn.net/weixin_41799019/article/details/127325948

1. 引例

之前我们探讨过可重复读隔离级别下,事务T启动的时候会创建一个视图read-view。在事务T执行期间,即使有其他事务修改了数据,事务T看到的也是跟启动时一样的。

但是上次讲到行锁的时候,当事务T要更新当前行的时候,其他事务占据了该行的行锁。那等
其他事务更新完,事务T要更新当前行的时候,看到的值又是多少呢?

首先,我们创建一个表,然后插入两行数据

mysql>CREATE TABLE t(id int(11) not null,k int(11) default null,primary key id
)ENGINE=InnoDB;
insert into t(id,k) values(1,1),(2,2);

然后分别执行事务A、事务B、事务C
在这里插入图片描述

这里我们需要注意事务的启动时机,启动实际是存在两种方式的:

  1. begin/start transaction:这种命令的启动方式并不是立即启动事务,而是到执行第一个InnoDB的操作语句时,事务才真正启动。也就是说一致性视图是在第一个快照读语句时创建的
  2. start transaction with consistent snapshot:这种命令的启动方式能够立即启动事务。也就是说一致性视图是在执行该语句的时候就创建了

对于上图中,事务C没有显式地启动事务,但是执行完update语句就会立马提交。事务B在更新了行之后查询。事务A是一个只读地事务,且在事务B和事务C更新之后进行查询。

最终的答案是,事务A看到的值是1,事务B看到的值是3。

在MySQL中视图有两个含义:

  1. view:一个用查询语句定义的虚拟表,创建视图的语法是create view…
  2. consistent read view:InnoDB在实现MVCC时用到的一致性读视图,用于支持Read Committed(读提交)和Repeatable Read(可重复读)隔离级别的实现。

2. 快照在MVCC中是如何工作的?

在可重复读隔离级别下,事务在启动的时候就建立了一张快照,并且这个快照是基于整库的

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

而每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新版本的数据,并且把transaction id赋值给这个数据版本的事务ID,记为row trx_id。也就是说,数据表中的一行数据,其实可能有多个版本,每个版本有自己的row trx_id。

如下图所示,就展现了一个记录被多个事务更新的状态。
在这里插入图片描述

V1、V2、V3并不是物理上实际存在的,而是每次需要的时候根据当前版本和redo log(回滚日志)计算出来的。比如,需要V2的时候,通过V4依次执行U3、U2算出来的。

接下来,我们来看快照是如何生成的?

根据可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果。但是之后,这个事务执行期间,其他事务的更新对它不可见。
也就是说,如果一个事务是在我启动之前生成的,就认。如果是我启动之后生成的,我就不认,必须要找到上一个可见的版本。此外,如果这个事务自己更新的数据,也是要认的

在具体实现的时候,InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”是指启动了但还没提交。

数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。这个视图数组和和高水位,就组成了当前事务的一致性视图

数据版本的可见性规则,就是基于数据的row trx_id和这个一致性视图对比结果得到的。如下图,分为以下几种情况:

在这里插入图片描述

对于当前事务的启动瞬间,一个数据版本的row trx_id,有以下几种可能:

  1. 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的。
  2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的。
  3. 如果落在黄色部分,那就包含两种情况
    • 若row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
    • 若row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

接着上面的说,对于第一个图中,如果有一个事务,它的低水位是18,那么当访问到这行数据的时候,就会从V4回滚到V3,在他看来,这一行的值是11。InnoDB利用了“所有数据都有多个版本”实现了秒级快照的能力。

然后,我们再回到最开始的引例,分析下为什么事务A看到的值是k=1。
我们先做如下的假设:

  1. 事务A开始前,系统分配的最大transaction id为99;
  2. 则事务A、B、C的版本号分别为100、101、102,且当前系统只有这四个事务;
  3. 三个事务开始前,(1,1)这行数据的row trx_id是90;

基于此,事务A的视图数组为[99,100],事务B的视图数组为[99,100,101],事务C的视图数组为[99,100,101,102]。数据版本的展示如下:
在这里插入图片描述

事务A查询语句读取数据的流程是这样的

  1. 找到(1,3)的时候,发现row trx_id=101,比高水位大,处于红色区域,不可见。
  2. 找到上一个历史版本(1,2),发现row trx_id=102,比高水位大,处于红色区域,不可见。
  3. 再找到上一个历史版本(1,1),发现row trx_id=90,比低水位小,处于绿色区域,可见。

但是上面这种判断方法太麻烦,我们可以简化判断方法

  • 前提:除了自己的更新总是可见之外
  • 版本未提交,不可见
  • 版本已提交,但是在视图创建后提交,不可见
  • 版本已提交,但是在视图创建前提交,可见。

我们再基于这种方法来判断事务A的查询流程:

  1. (1,3)还没提交,属于情况1,不可见
  2. (1,2)提交了,但是在视图数组创建之后提交的,属于情况2,不可见
  3. (1,1)是在视图数组创建之前提交的,可见。

3. 更新逻辑

可能你会发现,如果按照上面的逻辑,事务B不应该也看不见(1,2)吗?下面是事务B的事务逻辑图:
在这里插入图片描述

如果事务B只更新数据的话,那看到的确实是(1,1)。但是事务B先更新了数据,那么就不能在历史版本上更新了,否则就会出现丢失更新的情况。因此事务B的set k=k+1是在(1,2的基础上)完成的。

所以这里用到了一条规则:更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。 因此,在执行事务B查询语句的时候,自己的版本号和最新的数据版本号都是101,所以查询得到k的值是3。

其实除了update语句外,select语句如果加锁,也是当前读。
因此,如果把事务A的查询语句,加上lock in share mode或for update,也都是返回k等于3。如下面这两个select语句,就是分别加了读锁和写锁。

mysql> select k from t where id=1 lock in share mode;
mysql> select k from t where id=1 for update;

再分析另外一种情况,如果事务C不是马上提交会怎么样?如下图:
在这里插入图片描述

因为事务C先将k修改为2,根据之前的两阶段协议,由于还没有提交,所以事务C会持有该行的行锁,直到事务提交才释放。又由于事务B是当前读,必须要读到最新版本,所以就需要等待事务C释放了锁才能修改值。如下图所示:
在这里插入图片描述

接下来,我们总结下事务的可重复读的能力是如何实现的
可重复读的核心就是一致性读;而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进行等待。

而对于读提交的逻辑其实也很像,主要区别在于?

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的查询都共用这个一致性试图。
  • 在读提交的隔离级别下,每一个语句执行前都会重新计算出一个新的视图。

那么在读提交的隔离级别下,事务A和事务B查询到的值是多少呢?
在这里插入图片描述

事务B的查询结果为k=3.但是由于事务B还没提交,事务C提交了,所以事务A的查询结果为k=2。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_23434.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring-Framework-ioc-4

1前言 2基本原理 3IOC容器 4Bean 5依赖 5.1依赖注入 5.2自动装配 自动装配,是一种自动化地进行依赖注入的机制,IOC容器使用此机制实现bean之间依赖关系的自动绑定,该机制具有如下的优点: 不需要显式地指定依赖的属性域、构…

基于STC89C52单片机的蔬菜大棚实时温度测量控制系统

目录 摘要 …………………………………………………………………………………I ABSTRACT II 第一章 设计任务及方案分析 1 1.1 设计任务及要求 1 1.2 设计总体方案及方案论证 1 1.3 温度测量的方案与分析 1 1.31芯片选择 1 1.32实现方法简介 2 1.33 方案设计 2 第二章 芯片简介…

Java基础(二):集合、IO流(Zip压缩输入/输出流等)、File文件类、反射、枚举

Java基础(一):编译和解释、数据类型、变量作用域、String常用方法、数组、面向对象、异常 Java基础(二):集合、IO流(Zip压缩输入/输出流等)、File文件类、反射、枚举 Java异常、继承结构、处理异常、自定义异常、SpringBoot中全…

数据库学习记录2

数据库学习记录1介绍了DDL (Data Definition Language) 数据定义语言。 在数据库学习记录2中,我们介绍常见的数据类型; 主要分为三类:数值类型、字符串类型、日期时间类型。 数值类型 类型大小有符号范围无符号范围描述TINYINT1byte(-128&…

生成模型笔记(七):自回归模型

有鸟止南方之阜,三年不翅,不飞不鸣,嘿然无声,此为何名? 第七部分 深度自回归模型(Deep Autoregressive Model, DARM) 参考内容 https://jmtomczak.github.io/blog/2/2_ARM.html A…

第二十三:Fiddler抓包教程(23)-Fiddler如何优雅地在正式和测试环境之间来回切换-上篇

一.简介 1.在开发或者测试的过程中,由于项目环境比较多,往往需要来来回回地反复切换,那么如何优雅地切换呢? 二.实际工作场景 1.问题场景 1.1.已发布线上APP出现接口错误,如何测试线上APP访问本地请求?…

QFramework v1.0 使用指南 介绍篇:01. 简介

01. 简介 大家好,我是 QFramework 的作者 凉鞋,QFramework 从第一次代码提交到现在快 7 年了(2015 年 12 月 ~ 2022 年 10 月)了,而经过了 7 年时间的打磨,我们终于迎来了 v1.0 版本。 此教程&#xff0c…

Macos/linux g++ 安装OpenCV环境

本文前半部分主要翻译官方文档的东西 https://docs.opencv.org/4.x/d0/db2/tutorial_macos_install.html 依赖: CMake 3.9 or higher Git Python 2.7 or later and Numpy 1.5 or later大家都是程序员自己安装一下吧 在 relese 这里下载一下源代码: htt…

第三章:为组件库添加规范【前端工程化入门-----从零实现一个react+ts+vite+tailwindcss组件库】

第三章:为组件库添加规范 本章我们会用 eslint、prettier以及Husky 为组件库添加规范; 前置知识: eslint、prettier和husky各有什么作用? eslint是代码检查工具,你可以配置eslint,然后通过lint命令检测…

打游戏哪款蓝牙耳机好?四款适合打游戏的蓝牙耳机推荐

现在年轻人最离不开的就是手游,蓝牙耳机可谓是手机游戏的最佳搭档,一副好的蓝牙耳机可以为游戏带来很完美的助力,延迟低的蓝牙耳机可以实现更好的游戏体验感,那么接下来推荐四款适合打游戏的蓝牙耳机。 1、南卡小音舱蓝牙耳机 佩…

2022年全国大学生数学建模美赛E题NPP数据获取

今年的数学建模美赛终于开始了!令我感到欣喜的是,今年E题竟然和地理遥感专业息息相关。E题是分析生态环境方面的!因此,有很多小伙伴来询问咨询如何解决这道题目。有些小伙伴,还咨询如何使用CASA软件来计算NPP数据&…

Flink SQL使用Catalog消费Kafka时,多个Source读取同一主题解决方案

一、Catalog定义 Catalog 提供了元数据信息,例如数据库、表、分区、视图以及数据库或其他外部系统中存储的函数和信息。数据处理最关键的方面之一是管理元数据。 元数据可以是临时的,例如临时表、或者通过 TableEnvironment 注册的 UDF。 元数据也可以是…

apollo在虚拟机下部署遇到的坑

目录问题描述解决方法编译问题总结问题描述 ​   其实在虚拟机下部署apollo网上是有线程教程的。可以参考在虚拟机上安装运行百度Apollo 6.0,Apollo 6.0 安装完全指南。我依靠这两个指南准备部署的是apollo 7.0,事实证明虽然版本不同,但部…

1、6边距复合属性

提示:文章写完后,padding可以有到四个值。 1、语法: div{ padding:“50px”; padding:“5px 10px”; padding:“5px 10px 20px”; padding:“5…

flex竖排列元素排列方向

flex竖排列元素排列方向一、flex-direction: (元素排列方向) ※ flex-direction:row (横向从左到右排列==左对齐)※ flex-direction:row-reverse (与row 相反)※ flex-direction:column (从上往下排列==顶对齐)※ flex-direction:column-reverse (与column 相反) 二…

基于导频的信道估计实现

目录 零、前言 一、为什么要信道估计 二、导频的概念 (1)为什么要有导频 (2)导频在信道估计中作用 (3)关于导频序列的补充 三、最小二乘法估计 (1)LS信道估计算法分析 &…

24.登录form的显示

1.概括 本次博客的代码就不自己去写输入框了,直接去引用element官网中的就好。 具体如何实现可以去订阅Vue专栏中的最后两节课噢!!!!!!2.操作方法 打开element官网 https://element.eleme.cn/…

TRC丨艾美捷TRC 那非那韦亚砜说明书

艾美捷TRC Nelfinavir Sulfoxide 是 Nelfinavir Mesylate (N389750) 的杂质。Nelfinavir USP 相关化合物 A。 艾美捷TRC 那非那韦亚砜化学性质: 目录号N389770 化学名称那非那韦亚砜 同义词(3S,4aS,8aS)-N-(1,1-二甲基乙基)十氢-2-[(2R,3R)-2-羟基-3-[(3-羟基-2-…

合宙AIR32F103CBT6刷回CMSIS-DAP固件以及刷ST-LINK V2-1固件方法

合宙AIR32F103CBT6刷回CMSIS DAP固件以及刷ST-LINK V2-1固件方法📌官方介绍文档:https://wiki.luatos.com/chips/air32f103/index.html📍原理图:https://cdn.openluat-luatcommunity.openluat.com/attachment/20220605164915340_AIR32CBT6.pd…

从零备战蓝桥杯——动态规划(递推篇)

双非刷leetcode备战2023年蓝桥杯,qwq加油吧,无论结果如何总会有收获!一起加油,我是跟着英雄哥的那个思维导图刷leetcode的,大家也可以看看所有涉及到的题目用leetcode搜索就可以哦,因为避让添加外链,一起加…