MySQL学习笔记(一)数据库事务隔离级别与多版本并发控制(MVCC)

一、数据库事务隔离级别

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted (读未提交)、Read committed(读提交) 、Repeatable read(可重复读) 、Serializable (串行化)。

1、脏读、不可重复读、幻读

在数据库多个事务并发执行的情况下,不同的隔离级别可能会出现脏读、不可重复读、幻读这几种问题。

脏读:读取到未提交的数据。事务A对某条数据进行了修改,但还未提交,这时事务B读取到了这条未提交的数据。如果事务A出错回滚,事务B读取到的数据就是一条脏数据。
不可重复读: 同一事务内多次查询某条数据的结果不一致。事务A对某条数据执行了两次查询,在这两次查询的时间间隔内,事务B对该条数据执行了修改(update),导致事务A的两次查询结果不一致。
幻读: 同一事务内多次查询的结果集不一致(多或少了几条数据)。事务A以相同的查询条件执行了两次查询,在这两次查询的时间间隔内,事务B新增或删除(insert|delete)了几条数据,导致事务A的两次查询结果集不一致。

2、四种隔离级别

读未提交 (Read uncommitted)
最低隔离级别,允许事务读取其他事务未提交的更改。可能导致脏读、不可重复读、幻读问题。

读提交(Read Committed)
事务只能读取到已提交的数据。可以解决脏读问题,但是还会有可能不可重复读、幻读问题。

可重复读(Repeated Read)
专门针对“不可重复读”这种情况而制定的隔离级别。可以解决脏读和不可重复读问题,但还是有可能出现幻读问题。MYSQL默认的隔离级别

串行化(Serializable)
最高隔离级别,所有事务都串行化顺序执行,不存在并发,从而完全防止脏读、不可重复读和幻读问题。但是这种隔离级别性能较低,基本不会使用。

二、多版本并发控制(MVCC)

1、什么是多版本并发控制(MVCC)

多版本并发控制英文全称是 Multiversion Concurrency Control,简称 MVCC。

MVCC是通过保存数据行的历史版本,组成版本链,对比事务ID与版本号来确定当前事务应该使用哪个历史版本数据,而无需加锁就可以保证事务的隔离效果,可以认为是一种不加锁的行锁,可以提高数据库的性能。

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。不仅是MySQL,包括Oracle、PostgreSQL等其他数据库系统也都实现了MVCC,但各自的实现机制不尽相同,因为MVCC没有一个统一的实现标准,典型的有乐观(optimistic)并发控制和悲观(pessimistic)并发控制。

2、MVCC可以解决哪些问题

(1)读写之间阻塞的问题
MVCC可以让读写操作互不阻塞,即读不阻塞写,写不阻塞读。相较于普通锁(串行运行)、读写锁(可以实现读读并发),MVCC提升数据库事务并发处理能力。
(2)降低了死锁的概率
MVCC大多数情况不用加锁,写数据时也只是加行锁,降低了死锁的概率
(3) 解决一致性读的问题
一致性读也叫快照读,当查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,或者本事务提交的结果,而不能看到这个时间点之后事务提交的更新的结果。

3、快照读与当前读

在MySQL InnoDB中,MVCC主要是为了提高数据库并发性能,以更好的方式处理读-写冲突,不用加锁实现并发读-写。这个读就是快照读,而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现。而MVCC本质是采用乐观锁思想的一种方式。
(1)快照读
快照读又叫一致性读,读取的是快照数据。是一种一致性不加锁的读。不加锁的简单的 SELECT 都属于快照读。例如:

SELECT * FROM t WHERE id=1

快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。
(2)当前读
当前读读取的是记录的最新版本(最新数据,而不是历史版本的数据),读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。加锁的 SELECT,或者对数据进行增删改都会进行当前读。

SELECT * FROM t LOCK IN SHARE MODE; # 共享锁SELECT * FROM t FOR UPDATE; # 排他锁INSERT INTO t values ... # 排他锁DELETE FROM t WHERE ... # 排他锁UPDATE t SET ... # 排他锁

4、InnoDB的MVCC原理

(1)隐藏字段和Undo Log版本链

隐藏字段:
对于使用 InnoDB 存储引擎的表来说,它的聚簇索引的叶子节点为数据页,存放的就是整张表的数据行,而每个数据行中有一些重要的隐藏字段。

  • DB_ROW_ID:大小为6字节,默认主键列,如果表没有设置主键,InnoDB会自动生成该隐藏主键列。
  • DB_TRX_ID:大小为6字节,生成该行数据历史版本的事务ID。
  • DB_ROLL_PTR:大小为7字节,回滚指针,指向上一个版本的Undo log,InnoDB 便是通过这个指针找到之前版本的数据,该行数据的所有版本记录都在undo中通过链表形式组织在一起。

另外每条记录的头信息(record header)里都有一个专门的 bit(deleted_flag)来表示当前记录是否已经被删除
Undo log版本链:
每次对数据行进行改动,都会生成一条undo日志,每条undo日志也都有一个 DB_ROLL_PTR属性,INSERT 操作对应的undo日志没有该属性,因为该记录并没有更早的版本。版本链示例如下:
在这里插入图片描述

(2)ReadView

在多事务并发修改同一行数据的情况下,MVCC通过隐藏字段和Undo Log生成了该行记录的历史版本快照,并组成了版本链。但是事务读取数据时该读取哪个版本的数据,需要一个读取机制来确定。这时就用到了ReadView(可读视图)
设计思路:
(1)使用 READ UNCOMMITTED 隔离级别的事务,由于可以读到未提交事务修改过的记录,所以直接读取记录的最新版本就好
(2)使用 SERIALIZABLE 隔离级别的事务,InnoDB规定使用加锁的方式来访问记录
(3)使用 READ COMMITTED 和 REPEATABLE READ 隔离级别的事务,都必须保证读到已经提交了的 事务修改过的记录。假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的,核心问题就是需要判断一下版本链中的哪个版本是当前事务可见的,这是ReadView要解决的主要问题

ReadView内容:
ReadView主要包含以下4个内容:
(1)creator_trx_id
创建当前ReadView的事务ID。注意只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务ID,否则在一个只读事务中的事务ID值都默认为0。
(2)trx_ids
生成ReadView时,当前系统活跃的事务ID集合,活跃的事务表示还未提交的事务。
(3)up_limit_id
活跃的事务中,最小的事务ID
(4)low_limit_id
表示生成ReadView时系统中应该分配给下一个事务的 id 值,即最大事务ID+1。

ReadView的规则:
(1)如果某行数据被访问版本的trx_id属性值与ReadView中的 creator_trx_id 值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

(2)如果某行数据被访问版本的trx_id属性值小于ReadView中的 up_limit_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。

(3)如果某行数据被访问版本的trx_id属性值大于或等于ReadView中的 low_limit_id 值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

(4)如果某行数据被访问版本的trx_id属性值在ReadView的 up_limit_id 和 low_limit_id 之间,那就需要判断一下trx_id属性值是不是在 trx_ids 列表中。
a. 如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问
b. 如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问

(3)MVCC快照读的整体流程

当查询一条记录的时候,系统通过如下流程MVCC找到合适的记录:

(1)首先获取事务自己的版本号,也就是事务 ID

(2)获取 ReadView

(3)查询得到的数据,然后与 ReadView 中的事务版本号进行比较

(4)如果不符合 ReadView 规则,就需要从 Undo Log 中获取历史快照

(5)最后返回符合规则的数据

如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性。以此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

(4)MVCC解决不可重复读和幻读原理

当隔离级别为读提交(Read Committed)时,一个事务中的每一次 SELECT 查询都会重新获取一次ReadView。当隔离级别为可重复读(Repeated Read)时,一个事务只在第一次 SELECT 的时候会获取一次ReadView,而后面所有的SELECT都会复用这个ReadView。

1)READ COMMITTED隔离级别

假设事务A、B的事务ID分别为10、20,并且事务正在执行,还未提交

# Transaction A ID=10
BEGIN;
UPDATE t SET name="李四" WHERE id=1;
UPDATE t SET name="王五" WHERE id=1;
# Transaction B iD=20
BEGIN;
UPDATE t SET name="赵六" WHERE id=1;

此时id为1的数据的版本链如下:
在这里插入图片描述
此时,另一个事务C开始执行

# 使用READ COMMITTED隔离级别的事务C ID=21
BEGIN;
# 事务A和B都未提交
# SELECT1
SELECT * FROM t WHERE id = 1; # 得到的列name的值为'张三'

SELECT1生成的ReadView的trx_ids=[10,20,21],up_limit_id=10,low_limit_id=22,creator_trx_id为0。从“赵六”那个版本开始查找,因为10、20都在trx_ids里,所以符合的版本只有trx_id=5的版本数据。

此时,把事务A提交

# Transaction A ID=10
BEGIN;
UPDATE student SET name="李四" WHERE id=1;
UPDATE student SET name="王五" WHERE id=1;
COMMIT;

然后在事务C中继续查询

# 使用READ COMMITTED隔离级别的事务C ID=21
BEGIN;
# 事务A和B都未提交
# SELECT1
SELECT * FROM t WHERE id = 1; # 得到的列name的值为'张三'
#SELECT2
SELECT * FROM t WHERE id = 1; # 得到的列name的值为'王五'

SELECT2会生成新的ReadView,新ReadView的trx_ids=[20,21],up_limit_id=20,low_limit_id=22,creator_trx_id为0。还是从“赵六”那个版本开始查找,此时只有20在trx_ids里。所以trx_id=10的版本对SELECT2是可见的,SELECT2查找到的结果就是“王五”那个版本数据。

2)REPEATABLE READ隔离级别

操作同上。但是在SELECT2时,REPEATABLE READ隔离级别是不会重新生成ReadView的,所以SELECT2使用的还是SELECT1的ReadView。所以查出来的结果和SELECT1是一致的,都是trx_id=5的版本数据。这样就解决了不可重复读的问题。

(5)MVCC解决幻读原理

假设表t中有一条id为1的数据,trx_id=10
在这里插入图片描述

现在有事务A(ID=20)、事务B(ID=30)并行执行

# Transaction A ID=20
BEGIN;
#SELECT1
SELECT * FROM t WHERE id >= 1; 

SELECT创建的ReadView的内容为trx_ids=[20,30] , up_limit_id=20 , low_limit_id=31 , creator_trx_id=0。根据ReadView的规则,id=1的数据的trx_id=10<up_limit_id,所以事务A能查出来。

此时,事务B插入两条数据,并提交

# Transaction B ID=30
BEGIN;
insert into t(id,name) values(2,'李四');
insert into t(id,name) values(3,'王五');
COMMIT;

然后,事务A再次查询

# Transaction A ID=20
BEGIN;
#SELECT1
SELECT * FROM t WHERE id >= 1; 
#SELECT2
SELECT * FROM t WHERE id >= 1; 

因为是REPEATABLE READ隔离级别,SELECT2不创建新的ReadView,使用SELECT1的ReadView。ReadView的内容为trx_ids=[20,30] , up_limit_id=20 , low_limit_id=31 , creator_trx_id=0。因为id为2,3的两条数据的trx_id=30,在trx_ids里,所以事务A不能查出来。
在这里插入图片描述
所以MYSQL的InnoDB在REPEATABLE READ隔离级别下,不会出现幻读的情况。

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

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

相关文章

如何在异步结果返回时进行跟踪

当我在使用多进程池时&#xff0c;可以通过apply_async()方法提交任务&#xff0c;并使用get()方法获取异步任务的结果。但是&#xff0c;在等待结果返回时&#xff0c;我们最希望能够跟踪任务的进度&#xff0c;以及处理已完成任务的结果。 然后针对这种问题我们最常见的方法…

国际数字影像产业园会议中心助力打造舒适高端的会议目的地

国际数字影像产业园会议中心&#xff0c;作为集先进技术与卓越设计于一体的现代化会议场所&#xff0c;正日益成为国内外高端会议活动的首选之地。其独特的建筑风格和内部设施&#xff0c;为与会者提供了舒适而高效的环境&#xff0c;让每一次大中小型会议都能达到预期的效果。…

如何关闭远程桌面连接

远程桌面连接是一种方便的技术&#xff0c;可以让用户通过网络远程访问其他计算机的桌面界面。有时候我们可能需要关闭这个连接。本文将向你介绍如何关闭远程桌面连接。 关闭远程桌面连接的步骤 要关闭远程桌面连接&#xff0c;按照以下步骤操作&#xff1a; 打开远程桌面连接…

最简单 导航栏 html css

dhl.html <!DOCTYPE html> <html><head><meta charset"utf-8"><title>导航栏</title><link type"text/css" rel"stylesheet" href"css/dhl.css"></head><div class"dhl&quo…

数据分析案例-二手车用户数据可视化分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【深度学习笔记】计算机视觉——风格迁移

风格迁移 摄影爱好者也许接触过滤波器。它能改变照片的颜色风格&#xff0c;从而使风景照更加锐利或者令人像更加美白。但一个滤波器通常只能改变照片的某个方面。如果要照片达到理想中的风格&#xff0c;可能需要尝试大量不同的组合。这个过程的复杂程度不亚于模型调参。 本…

leetcode 11.盛最多水的容器

题目链接&#xff1a;https://leetcode.cn/problems/container-with-most-water/ 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以…

【unity实战】事件(Event)的基本实战使用

文章目录 最终效果前言一、素材二、角色金币交互1. 拾取金币2. 显示金币数UI 完结 最终效果 前言 之前我们介绍过委托的用法&#xff0c;具体可以跳转&#xff1a;【unity小技巧】委托&#xff08;Delegate&#xff09;的基础使用和介绍 这期来讲讲事件&#xff0c;使用你会发…

【SpringBoot3.x教程02】SpringBoot配置文件详解

前言&#xff1a;什么是配置文件 SpringBoot的配置文件是指用于定义和管理SpringBoot应用程序配置的文件。这些配置文件允许开发者调整和控制应用程序的行为&#xff0c;而无需改变代码。主要有两种格式的配置文件&#xff1a; 1、application.properties&#xff1a;这是一种使…

华金证券2024:以“芯”助先进算法,以“算”驱万物智能

本文选自“以芯助先进算法&#xff0c;以算驱万物智能”。 一、半导体景气度有望迎来复苏 从半导体行业景气度来看&#xff0c;在经历了2022、2023年的去库存周期 后&#xff0c;半导体销售额有望在2024年迎来复苏。据WSTS数据显示&#xff0c;全球半导体产品销售总额从1999 年…

OJ_一端进,两端出

题干 C实现 #include <stdio.h> #include <list> #include <vector>using namespace std;int main() {int n, k;scanf("%d%d", &n, &k);vector<int> insertVec(n);for (int i 0; i < n; i) {scanf("%d", &insert…

四、西瓜书——支持向量机

第六章 支持向量机 1.间隔与支持向量 支持向量机的原理是寻找与支持向量具有最大间隔的划分超平面。支持向量机具有一个重要性质: 训练完成后,大部分的训练样本都不需保留,最终模型仅与支持向量有关. 首先&#xff0c;超平面的方程为&#xff1a; 点到超平面的距离为&#xff…

单表练习12.0

一个学生表 分别记录姓名&#xff0c;年龄&#xff0c;性别&#xff0c;班级&#xff0c;语文&#xff0c;数学&#xff0c;英语字段 create table student2( id int primary key , name char(20), sex char(10), age int(3), mobile char(20), class char(10), engli…

男子失眠焦虑、胸闷气短发作,多次跑医院,检查结果却显示无异常!

植物神经紊乱指的是人体内部的自主神经系统失去平衡&#xff0c;导致一系列的生理和心理方面的异常状态。人体的自主神经系统分为交感神经系统和副交感神经系统&#xff0c;它们共同调节心血管系统、消化系统、呼吸系统、内分泌系统等器官的功能。当这两个系统的平衡被打破&…

IPSEC---VPN

文章目录 目录 文章目录 一.TCP/IP 协议的缺点 二.IPsec诞生背景 IPsec可提供安全服务 三.IPsec协议簇 IPsec的两种工作模式 传输模式 隧道模式&#xff1a; IPsec的安全协议 AH 协议:鉴别头协议 ESP协议&#xff1a;封装安全载荷协议 AH与ESP对比 AHESP报文&#xff1a…

【Python】Python注册微服务到nacos

Python注册微服务到Nacos 1.Nacos部署 github 的nacos项目的发布页&#xff08;Releases alibaba/nacos GitHub &#xff09;&#xff0c;选择所要下载的nacos版本&#xff0c;在nacos下方的assets中选择安装包进行下载。 解压nacos安装包到指定目录。 tar -zxvf nacos-ser…

国产通讯芯片D3232介绍,要用于工控主板、工业控制器、程序烧录下载器、仿真器、新能源充电桩等众多涉及RS232通讯的产品

一、应用领域 D3232芯片主要用于工控主板、工业控制器、程序烧录下载器、仿真器、新能源充电桩等众多涉及RS232通讯的产品。 二、基本特性 D3232芯片由两个线路驱动器、两个线路接收器和双电荷泵电路组成&#xff0c;具有HBM>15kV、CDM>2kV的ESD保护能力&#xff0c;并且…

element-ui plus v2.60 终于修复了 radio checkbox 取值不明确的问题,label value 值

element-ui plus v2.60 终于修复了 radio checkbox 取值不明确的问题&#xff0c;label value 值 昨天想反馈这个关于 label 和 value 的问题的时候&#xff0c;发现新版本已经修正这个问题了。 一、ElementUI 旧版关于 label 和 value 的问题 从之前 element-ui 用过来的&a…

两天学会微服务网关Gateway-Gateway网关限流

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…

Sublime Text 格式化Json文件 之 Pretty Json

需要使用到 Pretty Json插件。 一、安装方法 sublime 下&#xff0c;按快捷键 Comand control p&#xff0c; 输入install Package,然后回车 等几秒钟&#xff0c;加载启动进程完毕后弹出的页面中输入pretty json, 然后回车 等待几秒钟&#xff0c;可以查看Sublime 最下面的…