Mysql 学习(十七)事务隔离级别和MVCC

前提准备

  • 首先创建一个表:
CREATE TABLE hero (number INT,name VARCHAR(100),country varchar(100),PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8;INSERT INTO hero VALUES(1, '刘备', '蜀');

事务隔离级别

  • mysql 是一个 客户端 和 服务器架构的软件,对于同一个服务器来说,可以有许多的客户端与之链接,每个客户端与服务器连接之后,就可以称之为一个会话,每个客户端都可以在自己的会话中向服务器发出请求语句,每个语句可能就是事务的一部分,假设事务的隔离性特别高,则事务需要排队请求某一个数据,这个时候对于性能的影响就太大了,所以mysql 会有不同的隔离级别,每个隔离级别舍弃了一部分隔离性来维持性能

事务并发执行遇到的问题

  • 我们先假设事务没有隔离性,不是串行执行,而是并发执行

脏写

  • 如果一个事务修改了另一个事务修改过的数据,就意味着产生了脏写,具体例子如下:在这里插入图片描述
  • Session A 都已经提交了,但是 Session B 却最后rollback了,所以 Session A 会发现自己根本没有做修改

脏读

  • 如果一个事务读取另一个事务修改过的数据,就意味着产生了脏读,具体例子如下:在这里插入图片描述
  • Session A 和 Session B 各自开启了一个事务,然后Session A 的事务中 使用select 语句查询出了 Session B中 修改的数据,相当于 Session A 读取了一个不存在的数据

不可重复读

  • 如果一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值,那就意味着发生了不可重复读,例子如下:在这里插入图片描述

幻读

  • 如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,那就意味着发生了幻读,例子如下:在这里插入图片描述

SQL标准四种隔离级别

  • 上面说的这四种问题,根据严重程度排序为:脏写 > 脏读 > 不可重复读 > 幻读
  • 隔离等级从小到大,就是舍弃一些,允许一些问题发生
  • sql 主要有以下四种隔离级别:
    • READ UNCOMMITTED:未提交读。
      • 可能发生的问题
        • 脏读
        • 不可重复读
        • 幻读
    • READ COMMITTED:已提交读。
      • 可能发生的问题
        • 不可重复读
        • 幻读
    • REPEATABLE READ:可重复读。
      • 可能发生的问题 (mysql这个级别不会发生这个问题)
        • 幻读
    • SERIALIZABLE:可串行化。不发生问题

MVCC

版本链

  • 对于innodb 来说 每个记录会包含必要的两个字段:
    • trx_id :事务ID
    • roll_pointer :每次对某条聚簇索引进行改动时,都会把旧的版本写入到undo 日志 中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。
  • 还记得我们之前创建的那张表和那条记录吗,假设那条记录的事务是80,然后我们又开启两个事务100,200,并进行了一些操作:在这里插入图片描述
  • 然后对应这条记录的版本链如下:在这里插入图片描述
  • 对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id

ReadView

  • 对于READ UNCOMMITTED隔离级别的事务来说,可以读到未提交的事务,所以直接获取记录最新的版本就好了,但是对于SERIALIZABLE 级别的事务来说,就要使用加锁的方式来访问
  • 但是对于 READ COMMITTED和REPEATABLE READ隔离级别的事务来说,必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的
  • 但是这里有个核心的的问题,你怎么知道这个记录版本链中那个版本是当前事务可见的
  • 为此提出了一个ReadView 的概念,这个数据结构包含了四个很重要的参数:
    • m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
    • min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
    • max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
    • creator_trx_id:表示生成该ReadView的事务的事务id
  • 有了这个readview 结构之后,我们访问某条记录,既可以根据下面这个步骤去判断记录的某个版本是否可见:
    • 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
    • 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
    • 如果被访问版本的trx_id属性值大于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
    • 如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间,那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
  • 根据这个规则我们就知道为啥可以这两个隔离事务可以避开 脏写,但是为什么READ COMMITTED 有不可重复读的问题,而REPEATABLE READ 没有呢?
  • 这个就跟他们的生成 readview 的时机不同导致了,下面我们就来根据两个事务 100,200 的操作来了解整个过程

READ COMMITTED —— 每次读取数据前都生成一个ReadView

  • 在事务 100 执行:
BEGIN;UPDATE hero SET name = '关羽' WHERE number = 1;UPDATE hero SET name = '张飞' WHERE number = 1;
  • 在事务200 执行:
更新别的表记录
  • 当前这条记录的版本号:
    在这里插入图片描述

  • 此时我们开启一个新的事务,整个事务是READ COMMITTED级别,我们进行查询:

# SELECT1:Transaction 100、200未提交
SELECT * FROM hero WHERE number = 1; # 得到的列name的值为'刘备'
  • 过程如下:

    • 先 生成一个 readview ,m_ids:[100,200],min_trx_id:100,max_trx_id:201,creator_trx_id:0
    • 然后跟最新列进行比对,发现 此纪录的事务100 在 m_ids 列表内,就跳过,接着访问下一条
    • 如此就访问到 name = ‘刘备’ ,发现这个事务ID 符合要求,就返回这条记录
  • 执行完这条sql 之后,事务id 为 100已经提交了,版本链就如下:
    在这里插入图片描述

  • 当前事务我们我们继续执行查询操作:

# 使用READ COMMITTED隔离级别的事务
BEGIN;# SELECT1:Transaction 100、200均未提交
SELECT * FROM hero WHERE number = 1; # 得到的列name的值为'刘备'# SELECT2:Transaction 100提交,Transaction 200未提交
SELECT * FROM hero WHERE number = 1; # 得到的列name的值为'张飞'
  • select 2 的执行过程如下:
    • 又单独 生成一个 readview ,m_ids:[200],min_trx_id:200,max_trx_id:201,creator_trx_id:0
    • 然后跟最新列进行比对,发现 此纪录 name 的内容是 ‘诸葛亮’ 的事务200 在 m_ids 列表内,就跳过,接着访问下一条
    • 如此就访问到 name = ‘张飞’ ,发现这个事务ID 100 符合要求,就返回这条记录
  • 所以我们两次查询会有不同的结果,因为使用READ COMMITTED隔离级别的事务在每次查询开始时都会生成一个独立的ReadView。

REPEATABLE READ —— 在第一次读取数据时生成一个ReadView

  • 接下来我们看如果我们的事务隔离级别是REPEATABLE READ,会是怎么样的
# 使用READ COMMITTED隔离级别的事务
BEGIN;# SELECT1:Transaction 100、200均未提交
SELECT * FROM hero WHERE number = 1; # 得到的列name的值为'刘备'# SELECT2:Transaction 100提交,Transaction 200未提交
SELECT * FROM hero WHERE number = 1; # 得到的列name的值为'刘备'
  • select 1 过程如下:
    • 先 生成一个 readview ,m_ids:[100,200],min_trx_id:100,max_trx_id:201,creator_trx_id:0
    • 然后跟最新列进行比对,发现 此纪录的事务100 在 m_ids 列表内,就跳过,接着访问下一条
    • 如此就访问到 name = ‘刘备’ ,发现这个事务ID 符合要求,就返回这条记录
  • select 2 过程如下:
    • 因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView ,m_ids:[100,200],min_trx_id:100,max_trx_id:201,creator_trx_id:0
    • 然后跟最新列进行比对,发现 此纪录 name 的内容是 ‘诸葛亮’ 的事务200 在 m_ids 列表内,就跳过,接着访问下一条
    • 如此就访问到 name = ‘张飞’ ,发现这个事务ID 100 符合要求,在 m_ids 列表内,就跳过,接着访问下一条
    • 如此就访问到 name = ‘刘备’ ,发现这个事务ID 符合要求,就返回这条记录
  • 结果就是 select 1 和 select 2 访问得到的结果都是一样的

小结:

  • 所谓的MVCC(Multi-Version Concurrency Control ,多版本并发控制)指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。READ COMMITTD、REPEATABLE READ这两个隔离级别的一个很大不同就是:生成ReadView的时机不同,READ COMMITTD在每一次进行普通SELECT操作前都会生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了。

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

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

相关文章

家庭Wi-Fi指南:2.4G还是5G?一文读懂!

📶 无线网络的双频选择:2.4GHz Wi-Fi vs 5GHz Wi-Fi 在享受无线网络的便捷时,我们通常会在设备上看到两个频段的Wi-Fi信号:2.4GHz和5GHz。这两个频段各有特点,了解它们的差异可以帮助你选择更适合你需求的网络连接。 …

SCAU 576 顺序线性表的基本操作

576 顺序线性表的基本操作 时间限制:1000MS 代码长度限制:10KB 提交次数:9027 通过次数:2456 题型: 编程题 语言: G;GCC Description 编写算法,创建初始化容量为LIST_INIT_SIZE的顺序表T,并实现插入、删除、遍历操作。本题目给出部分代码&#xff0c…

【数据结构】详解线性表的各个函数接口+OJ习题讲解(画图比写代码更重要!!!)

文章目录 一、线性表二、顺序表1、什么是顺序表2、顺序表的分类 三、动态顺序表的实现1、结构的定义2、顺序表的初始化3、检查容量4、在头部插入数据5、在尾部插入数据6、在指定位置插入数据7、在尾部删除数据8、在头部删除数据9、删除指定位置的数据10、查找数据11、修改指定位…

Linux: cloud: network: tap tx 丢包一例,vCPU的运行受到主机CPU的占用影响

https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/10/html/ovs-dpdk_end_to_end_troubleshooting_guide/high_packet_loss_in_the_tx_queue_of_the_instance_s_tap_interface 这个里面有一个丢包的例子是说,如果tx-queue的大小不够大&am…

ThreeJs制作模型图片

这个标题名字可能有歧义,只是不知道如何更好的表达,总之就是将图片的像素转换成3D场景的模型,并设置这个模型的颜色,放到像素点对应的位置从而拼接成一个图片,起因是上文中用js分解了音乐,实现了模型跳动效…

Oracle DBMS_LOCK

DBMS_lock是Oracle数据库中的一个包,主要用于控制并发和实现用户锁。在PL/SQL代码块中,有些操作代码块不能被多个会话同时进行执行,例如生成中间数据表等。如果此部分代码块被另个会话调用,则会造成中间数据表的数据在同一个会话中…

代码随想录算法训练营第七天|454. 四数相加 II

454. 四数相加 II 已解答 中等 相关标签 相关企业 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < nnums1[i] nums2[j] nums3[k] nums4[l] 0 示例 …

互联网行业的应届大学生,如何制作高水平简历?

雇主通常只会花大约25秒的时间浏览一份简历,因此,拥有一份出色的简历对于找到理想工作至关重要。如果您的简历没有令人印象深刻的特点,那么如何才能在竞争激烈的求职市场中脱颖而出呢? 如果您不知道如何在简历上有效地展示自己,或者觉得简历无论怎么修改都不够突出,那么请…

安装、配置MySQL

安装相关软件 MySQL Server、MySQL Workbench MySQL Server&#xff1a;专门用来提供数据存储和服务的软件 MySQL Workbench&#xff1a;可视化的 MySQL 管理工具 官网安装 https://www.mysql.com/ 官网 MySQL :: Download MySQL Installer 安装包路径 在这里选择版本和和对应…

多图如何导入多个二维码?图片批量导出二维码的技巧

多个图片分别生成对应的二维码怎么做&#xff1f;现在扫码看图片是一种很常用的内容预览方式&#xff0c;有些产品包装也会采用这种方式来展示对应的信息&#xff0c;怎么简单快速的将图片生成二维码&#xff0c;相信有很多的小伙伴都非常的感兴趣。那么小编通过下面这篇文章来…

力扣-28. 找出字符串中第一个匹配项的下标(内置函数或双指针)

找出字符串中第一个匹配项的下标 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; …

分布式微服务 - 3.服务调用 - 1.概念

分布式微服务 - 3.服务调用 - 1.概念 项目示例&#xff1a; 无 内容提要&#xff1a; 服务调用、负载均衡、框架降级熔断限流、框架网关、框架 文档&#xff1a; 无 服务调用 服务调用时&#xff0c;需要先获取服务消费者的ip和端口号等信息。因此&#xff0c;一般服务…

常见的特殊端口号及其用途

21端口&#xff1a;FTP&#xff08;文件传输协议&#xff09;服务端口。FTP允许用户进行文件传输&#xff0c;如上传和下载文件。22端口&#xff1a;SSH&#xff08;安全外壳协议&#xff09;服务端口。SSH用于远程登录到服务器&#xff0c;并提供加密的数据传输。23端口&#…

探索C++中的动态数组:实现自己的Vector容器

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

Python 装饰器decorator 圣经

文章目录 普通装饰器decorator0. 万能公式&#xff0c;非常重要1. 便于入门的decorator原理2. 理解函数3. 装饰器的作用:4. 装饰器的语法糖5. 装饰器顺序6. 极简的装饰器7. 装饰器的参数无参 函数装饰器有参 函数装饰器 类装饰器class decorator0. 万能公式&#xff0c;非常重要…

判断一个整数是不是2的阶次方

boolean check(){int sum 50;boolean flag true;while(sum > 1){if (sum % 2 0){sum sum % 2;}else {flag false;break;}}return flag;}

uView ScrollList 横向滚动列表

该组件一般用于同时展示多个商品、分类的场景&#xff0c;也可以完成左右滑动的列表。 #平台差异说明 App&#xff08;vue&#xff09;App&#xff08;nvue&#xff09;H5小程序√√√√ #基本使用 通过slot传入内容 <template><u-scroll-list><view v-for…

echarts line绘制机组开关状态折线图

2024.3.12今天我学习了如何用echarts line实现设备开关状态的效果。 代码如下&#xff1a; option {xAxis: {type: time,},yAxis: {type: value,splitNumber:2,// axisLine: {// show: true,// lineStyle: {// color:#808080// }// },axisLabel:{formatt…

管控员工上网行为(让老板管理更省心更高效)

很多老板都有这样一种顾虑&#xff1a; 员工到底有没有认真工作&#xff0c;工作是不是做到了全身心投入。 为什么会有担心员工工作状态的问题发生&#xff1f; 无疑是员工在上班时间浏览与工作无关的网站、下载私人文件、甚至是泄露公司机密等行为&#xff0c;让老板不放心了…

Elasticsearch:在本地使用 Gemma LLM 对私人数据进行问答

在本笔记本中&#xff0c;我们的目标是利用 Google 的 Gemma 模型开发 RAG 系统。 我们将使用 Elastic 的 ELSER 模型生成向量并将其存储在 Elasticsearch 中。 此外&#xff0c;我们将探索语义检索技术&#xff0c;并将最热门的搜索结果作为 Gemma 模型的上下文窗口呈现。 此外…