今天讲讲MYSQL数据库事务怎么实现的!

目录

什么是数据库事务

Mysql如何保证原子性

Mysql如何保证持久性

MySQL怎么保证隔离性

事务隔离级别

脏读的解决

不可重复读的解决

幻读的解决

MVCC实现

Read View

那么RC、RR级别下的InnoDB快照读有什么不同?


什么是数据库事务

数据库事务是指一组数据库操作,这些操作必须被视为一个不可分割的单元,要么全部执行成功,要么全部失败回滚。事务通常由多个SQL语句组成,这些语句可以读取、插入、更新或删除数据库中的数据。
事务具有ACID属性:

  1. 1. 原子性(Atomicity):事务的所有操作被视为单个原子操作,要么全部执行成功,要么全部执行失败回滚。

  2. 2. 一致性(Consistency):事务执行的结果必须使数据库从一个一致性状态转换到另一个一致性状态,其中包括所有数据完整性和约束性规则的应用。

  3. 3. 隔离性(Isolation):一个事务的执行不能被其他并发执行的事务干扰,每个事务应该感觉自己在独立地执行。

  4. 4. 持久性(Durability):一旦事务提交,其结果应该持久保存在数据库中,即使系统故障也应该如此。

通过实现事务,数据库系统可以确保数据的完整性和一致性,以及并发访问时的正确性。如果一个事务中的任何一个操作失败,整个事务将被回滚到最初的状态,这确保了数据库的一致性。

Mysql如何保证原子性

undo log名为回滚日志,是实现原子性的关键。InnoDB把这些为了回滚而记录的这些东西称之为undo log。这里需要注意的一点是,由于查询操作(SELECT)并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo logundo log主要分为3种:

  • • Insert undo log :插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。

  • • Update undo log:修改一条记录时,至少要把修改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。

  • • Delete undo log:删除一条记录时,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。

    • • 删除操作都只是设置一下老记录的DELETED_BIT,并不真正将过时的记录删除。

    • • 为了节省磁盘空间,InnoDB有专门的purge线程来清理DELETED_BIT为true的记录。为了不影响MVCC的正常工作,purge线程自己也维护了一个read view(这个read view相当于系统中最老活跃事务的read view);如果某个记录的DELETED_BIT为true,并且DB_TRX_ID相对于purge线程的read view可见,那么这条记录一定是可以被安全清除的。

举个栗子:

sqlundo log
insertdelete
deleteinsert
update T set v=3 where v=1update T set v=1 where v=3

Mysql如何保证持久性

通过Innodb架构解析我们了解到InnoDB 为了提升读写效率,引入了Buffer Pool(缓存池):

  • • 当数据库读取数据时,会首先从缓存池中读取

  • • 往数据库写入数据时,会先写入缓存池

  • • 缓存池中更新的数据会定期刷新到磁盘中

如果MySQL宕机,缓存池中更新的数据还没有刷回到磁盘中,就会导致数据丢失。于是,redo log被引入进来解决这个问题。

图片

  1. 1. 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝。

  2. 2. 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值。

  3. 3. 当事务commit时,将redo log buffer中的内容刷新到 redolog file,对 redo log file采用追加写的方式。

  4. 4. 定期将内存中修改的数据刷新到磁盘中。

redoundo在一次事务操作中是如何交互的?假设有A、B两个数据,值分别为1、2,开启事务分别对其进行修改A → 3,B → 4,在提交,过程如下:

事务redo&undo logo
begin;开启事务
记录A->3到redo log buffer
update T set A=3 where A=1;A修改为3
记录A=1到undo log
记录B->4到redo log buffer
update T set B=4 where B=2;B修改为4
记录B=2到undo log
记录A->3到redo log记录B->4到redo log
commit;事务提交

MySQL怎么保证隔离性

事务在并发情形下会互相干扰到的操作大体可以分为两类,与之相对应地,MySQL采用了两种方式来实现它们的隔离:

  1. 1. 一个事务的写操作对另一个事务的写操作的影响:锁机制保证隔离性

  2. 2. 一个事务的写操作对另一个事务的读操作的影响:MVCC保证隔离性

加锁:读取数据之前,对其加锁,阻止其他事务对数据进行修改

MVCC:不加任何锁,采用多版本并发控制实现,把数据库的行锁和行的多个版本结合起来,可以实现非锁定读,从而提高数据库的并发性能。

事务隔离级别

当数据库上有多个事务同时执行的时候,会带来以下问题:

问题描述举例
脏读一个事务读到了另一个事务未提交修改的数据。事务A开始一个更新操作,但是还没有提交,这时事务B读取了这个未提交的数据,就会产生脏读。
幻读一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据。事务A进行一个范围查询,此时事务B插入了一些符合该范围查询条件的新数据,当事务A再次进行相同的范围查询时,会发现多了一些之前没有的行,就产生了幻读。
不可重复读在一个事务中,多次查询的数据不一致。事务A读取了一行数据,然后事务B对这一行数据进行了更新,并且提交了,当事务A再次读取这一行数据时,会发现数据已经发生了变化,就产生了不可重复读。

为了避免这些问题的出现,数据库引入了隔离级别的概念,通过对不同隔离级别的设置,可以控制事务之间的隔离程度,从而避免并发问题的产生。不同的隔离级别有不同的特点和使用场景,需要根据实际情况进行选择。

以下是四个标准的事务隔离级别:

隔离级别含义脏读不可重复读幻读
读未提交,Read Uncommitted事务中的修改,即使没有提交,对其他事务都是可见的YYY
读已提交,Read Committed事务从开始到提交之前,所做的修改对其他事务都不可见NYY
可重复读,Repeatable read同一事务中多次读取同样的记录结果是一致的NNY
可序列化,Serializable在读取的每一行数据上加锁,强制事务串行执行NNN
脏读的解决

Innodb是通过在每行数据中增加一个隐藏的事务ID来实现mvcc,当一个事物开始时他会获取一个唯一的事务ID,该事务ID用来标记事务做的修改。当事务读取一行数据时,innodb会检查该行数据事务ID是否小于当前事务ID,如果是说明该行数据是未提交的数据,innodb会阻止该事务读取该行数据,从而避免了脏读的问题。

不可重复读的解决

innodb通过mvcc解决不可重复读的问题,在RR数据库隔离级别下,当我们使用快照进行数据读取的时候,只会在第一次读取的时候生成一个ReadView,后续所有快照读都是使用同一个快照,所以就不会发生不可重复读的问题了。

可重复读模式下举个栗子:事务隔离级别为RR:

图片

创建个测试表,并插入一条数据(1,1,1)

create table table1(id int(11) not null,a varchar(50) default null,b varchar(50) default null,primary key(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

分别开启两个事务测试:

事务1事务2
启动事务,查询如下:

图片

启动事务,查询如下:

图片

~将a改为2,可以查到

图片

查询a的结果还是1

图片

~提交事务

图片

再次查询a的结果还是1

图片

提交事务,再次查询a的结果变为2了

图片

幻读的解决

innodb的mvcc和间隙锁在一定程度上避免了幻读的发生,但是没有办法完全避免,当一个事务读的时候会导致幻读的发生。

幻读的case

  • • 创建一个用户表

    create table user(id int not null,name varchar(50),age int,primary key(id)
    );
  • • 插入几条数据

    insert into user values(1,'张三',10),(2,'李四',20),(3,'王二',30);

    图片

  • • 分别开启两个事务测试:

事务1事务2
begin;select * from user where age >10 and age<40;

图片

begin;insert into user value(4,'麻子',25);

图片

commit;
select * from user where age >10 and age<40;

图片

update user set name='呵呵' where age=25;select * from user where age >10 and age<40;

图片

MVCC实现

每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。

MySQL中每条记录,除了我们自定义的字段之外,还有数据库隐藏定义的三个字段:

字段描述
DB_TRX_ID6字节,最近修改事务id,记录创建这套记录后者最后一次修改该记录的事务id
DB_ROLL_PTR7字节,回滚指针,指向这条记录的上一个版本,用于配合undolog
DB_ROW_ID6字节,隐藏的主键,如果数据表没有主键,那么innodb会生成一个6字节的row_id

在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

InnoDB 并不会真正地去开辟空间存储多个版本的行记录,只是借助 undo log 记录每次写操作的反向操作。所以B+ 索引树上对应的记录只会有一个最新版本,InnoDB 可以根据 undo log 得到数据的历史版本,从而实现多版本控制。

Read View

什么是Read View,说白了Read View就是事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)

所以我们知道 Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,即可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

Read View遵循一个可见性算法,主要是将要被修改的数据的最新记录中的DB_TRX_ID(即当前事务ID)取出来,与系统当前其他活跃事务的ID去对比(由Read View维护),如果DB_TRX_ID跟Read View的属性做了某些比较,不符合可见性,那就通过DB_ROLL_PTR回滚指针去取出Undo Log中的DB_TRX_ID再比较,即遍历链表的DB_TRX_ID(从链首到链尾,即从最近的一次修改查起),直到找到满足特定条件的DB_TRX_ID, 那么这个DB_TRX_ID所在的旧记录就是当前事务能看见的最新老版本

假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。

图片

当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如图中看到的,在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到。同时你会发现,即使现在有另外一个事务正在将 4 改成 5,这个事务跟 read-view A、B、C 对应的事务是不会冲突的。你一定会问,回滚日志总不能一直保留吧,什么时候删除呢?答案是,在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的 read-view 的时候。

那么RC、RR级别下的InnoDB快照读有什么不同?

在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;

在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

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

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

相关文章

Geotrust SSL证书:安全加密与身份验证的坚实后盾

Geotrust&#xff0c;作为全球知名的数字证书颁发机构&#xff0c;以其高度的安全性、可靠性和广泛的兼容性&#xff0c;在网络安全领域中占据了举足轻重的地位。尤其在SSL&#xff08;Secure Sockets Layer&#xff09;证书服务上&#xff0c;Geotrust更是凭借其卓越的技术实力…

LongVLM:让大模型解读长视频 SOTA 的方法

LongVLM&#xff1a;让大模型解读长视频 SOTA 的方法 使用LongVLM处理长视频的步骤LongVLM 方法3.1 总体架构3.2 局部特征聚合3.3 全局语义整合 效果4.1 实验设置4.2 主要结果4.3 消融研究4.4 定性结果 论文&#xff1a;https://arxiv.org/pdf/2404.03384.pdf 代码&#xff1a…

组合数学<1>——组合数学基础

今天我们聊聊组合数学。(本期是给刚刚学习组合数学的同学看的&#xff0c;dalao们可以自行忽略) 建议:不会求逆元的出门左转数论<2>&#xff0c;不会数论的出门右转数论<1>。 加乘原理 加乘原理小学奥数就有。 总的来说:加法原理:分类;乘法原理:分步 比如说&a…

test4121

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

<Windows>【建议收藏】《Windows笔记本设置WIFI热点后经常自行断开如何解决?》

第一步&#xff1a;输入Win键x&#xff0c;打开设置 第二步&#xff1a;选择高级网络设置 第三步&#xff1a;点击下拉按钮选择编辑 第四步&#xff1a;选择配置 第五步&#xff1a;电源管理中取消勾选

取数游戏(dfs)

前言&#xff1a; 该题取自洛谷P1123&#xff0c;题主用的dfs&#xff08;深度优先搜索&#xff09; 题目描述&#xff1a; 数据范围&#xff1a; 思路&#xff1a; 思路见代码&#xff0c;注释的很清晰嗷 AC代码&#xff1a; #include <iostream> #include <alg…

Ubuntu系统使用Docker本地部署Android模拟器并实现公网访问

文章目录 1. 虚拟化环境检查2. Android 模拟器部署3. Ubuntu安装Cpolar4. 配置公网地址5. 远程访问小结 6. 固定Cpolar公网地址7. 固定地址访问 本文主要介绍如何在Ubuntu系统使用Docker部署docker-android安卓模拟器&#xff0c;并结合cpolar内网穿透工具实现公网远程访问本地…

【绩效管理】建立员工绩效考核机制,提升企业绩效管理水平

随着企业的迅猛发展&#xff0c;其内部管理问题日益突出&#xff0c;已经制约了企业的进一步发展。一方面&#xff0c;员工工作懒散、积极性不高&#xff0c;出错的次数也逐步上升&#xff0c;另一方面&#xff0c;管理者也无法有效评价员工的工作好坏。面对这些问题&#xff0…

Pillow教程11:九宫格切图的实现方法(安排!!!)

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

java混淆的重要性分析

Java代码混淆是一种常用的安全技术&#xff0c;它通过对Java代码进行变换和重命名&#xff0c;使得源代码变得难以理解和逆向工程&#xff0c;从而增强代码的安全性。以下是对Java混淆重要性的分析&#xff1a; 保护知识产权&#xff1a;Java混淆可以防止恶意用户或竞争对手轻易…

Vue笔记 2

数据代理 数据代理&#xff1a;通过一个对象代理对另一个对象中属性的操作&#xff08;读/写&#xff09; let obj{x:100} let obj2{y:200} Object.defineProperty(obj2,x,{get(){return obj.x},set(value){obj.x value} })Vue中的数据代理 Vue中的数据代理&#xff1a; 通…

MySQL学习笔记(三)

1、insert插入多条数据 语法&#xff1a;insert into t_user(字段名1,字段名2...) values(值1,值2...),(值1,值2...),(值1,值2...)...; 2、快速创建表 原理&#xff1a;将一个查询结果当做一张表创建&#xff0c;可以完成表的快速复制。表创建出来&#xff0c;同时表中的数据…

【计算机毕业设计】——农产品销售系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

✔ ★Java项目——设计一个消息队列(二)

Java项目——设计一个消息队列 四. 项⽬创建五. 创建核⼼类创建 Exchange&#xff08;名字、类型、持久化&#xff09;创建 MSGQueue&#xff08;名字、持久化、独占标识&#xff09;创建 Binding&#xff08;交换机名字、队列名字、bindingKey用于与routingKey匹配&#xff09…

LLMs之ToolAlpaca:ToolAlpaca(通用工具学习框架/工具使用语料库)的简介、安装和使用方法、案例应用之详细攻略

LLMs之ToolAlpaca&#xff1a;ToolAlpaca(通用工具学习框架/工具使用语料库)的简介、安装和使用方法、案例应用之详细攻略 目录 ToolAlpaca的简介 0、《ToolAlpaca: Generalized Tool Learning for Language Models with 3000 Simulated Cases》翻译与解读 1、数据集列表 2…

基于arcgis /envi PCA(主成分分析)实现过程

基于arcgis /envi PCA(主成分分析)实现过程 1 提取研究范围 2对研究范围进行重采样 &#xff08;根据数据情况进行选做&#xff0c;如数据较大建议进行该步骤操作&#xff09; 3 对研究范围内数据进行归一化处理 4 将空值替换为0 5 对同期不同要素数据进行波段合成 对波段…

Yii2 路由美化访问需要加s

不得不说yii真是反人类&#xff0c;怪不得现在都不维护了&#xff0c;今天解析下路由美化下的路由访问问题。 设置main.php配置文件 urlManager > [enablePrettyUrl > true, // 启用 URL美化showScriptName > false, // 隐藏入口文件index.phpenableStrictParsing…

MySql数据库从0-1学习-第三天多表设计学习

项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种: 一对多(多对一)多对多一对一 一对多 需求:根据需求,完成部门和员工表的设计 一对多,很多人会使用外键,…

如何分析 Java 开源项目源码?

准备深入分析一个 Java 开源项目的源码时&#xff0c;可以通过下面这些步骤和技巧&#xff0c;更系统地理解和分析项目源代码&#xff1a; 1. 确定分析目标和范围&#xff1a; 在开始分析之前&#xff0c;明确你的目标&#xff0c;确定你要深入了解的功能或模块。这有助于你有…

零基础转行网络安全,高薪梦想可以实现吗?

零基础转行网络安全&#xff0c;学会网络安全相关知识&#xff0c;可以从事以下岗位&#xff1a; 1、安全运维&#xff1a; 负责服务器及终端设备的维护 负责业务的安全风险评估和漏洞挖掘 负责安全事件的检查和实施 2、渗透测试 负责渗透测试、风险评估工作的实施 提供…