MySQL原理(四):事务

news2024/11/15 8:44:14

前言

上一篇介绍了 MySQL 的索引,这一篇将介绍事务相关的内容。

在 MySQL 的使用场景中,经常会有一个操作包含多个 SQL 语句,比如转账这个操作,至少包含从甲的账户中扣除金额和给乙的账户中增加金额这两个更新语句。那假如 MySQL 在执行途中发生了崩溃,就可能导致第一个操作成功而第二个操作失败,从而就会导致系统出错。为了解决这一类问题,MySQL 实现了事务,事务通常是由一组 SQL 组成的,这些 SQL 语句要么全部执行成功,要么全部执行失败,不会发生部分成功的情况。

实现事务(transaction)必须要遵守四个特性(ACID):

  • 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性(Consistency):是指事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态。以转账为例,事务操作的前后,系统中的总金额保持一致。
  • 隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致,因为多个事务同时使用相同的数据时,不会相互干扰,每个事务都有一个完整的数据空间,对其他并发事务是隔离的。
  • 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

并发问题

如果不对并发操作做任何限制,则会存在许多问题,常见的有脏读、不可重复读和幻读等问题。

脏读

如果一个事务「读到」了另一个「未提交事务修改过的数据」,就意味着发生了「脏读」现象。

不可重复读

在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了「不可重复读」现象。

幻读

幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行(即存在插入操作)。

隔离级别

SQL 标准提出了四种隔离级别来规避这些现象,隔离级别越高,性能效率就越低,这四个隔离级别按照隔离水平从低到高如下。

不同的事务隔离级别,其实是基于不同类型和粒度的锁实现的,后续会再详细介绍。

未提交读

Read Uncommitted,RU。是基于写互斥锁实现的,但是由于读操作并没有被阻塞,所以一个事务还没提交时,它做的变更就能被其他事务看到。因此可能存在脏读、不可重复读、幻读问题。

在该隔离级别下,执行完 SQL 语句后就会释放锁。

提交读

Read Committed,RC。在写互斥锁的基础上,使用了 MVCC 技术,当一个事务修改数据时,其他事务读取到的是旧数据的值,但是修改事务提交后,变更就能被其他事务读取到,所以可能存在不可重复读、幻读问题。

在提交读级别中,锁是在事务结束后才释放的。

可重复读

Repeatable Read,RR。和提交读一样使用了 MVCC,但是不是在每次查询时都创建新的 ReadView,而是在事务开始时创建,所以一个事务中的多次读取都是相同的,不会读取到其他事务做的变更。是 InnoDB 的默认隔离级别。仍然可能存在幻读问题。

在可重复读级别中,锁是在事务结束后才释放的。

MySQL 读取数据有两种读取模式:快照读和当前读。

  • 快照读(普通 select 语句,又称为一致性读):读的是快照生成时候的数据。是通过 MVCC 实现的。
  • 当前读(select … for update、select…lock in share mode、update、insert、delete):每次读取的都是当前最新的数据,但是读的时候不允许写,写的时候也不允许读。是通过临键锁实现的。

可重复读隔离级别能在很大程度上避免幻读现象:

  • 针对快照读,是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
  • 针对当前读,如果是读取行数据,则加记录锁;如果是读取范围行数据,则通过 next-key lock(记录锁+间隙锁)方式解决了幻读,加上 next-key lock 后,如果有其他事务在锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。

即使把所有的记录都加上锁,还是阻止不了新插入的记录,这也是为什么“幻读”会被单独拿出来解决的原因。也是间隙锁存在的意义。

但是仍然有可能发生幻读:

  • 对于快照读:MVCC 并不能完全避免幻读现象。因为当事务 A 更新了一条事务 B 插入的记录,那么事务 A 前后两次查询的记录条目就不一样了,所以就发生幻读。
  • 对于当前读,如果事务开启后,并没有执行当前读,而是先快照读,然后这期间如果其他事务插入了一条记录,那么事务后续使用当前读进行查询的时候,就会发现两次查询的记录条目就不一样了,所以就发生幻读。

串行化

Serializable。使用读写锁,将并发执行改为顺序执行,能从根源上避免并发问题,但是性能很差。

MVCC

Multiversion concurrency control,多版本并发控制。通过「版本链」来控制并发事务访问同一个记录时的行为。MVCC 主要通过隐藏字段、undo log、ReadView 来实现。

隐藏字段

在第一篇文章中介绍数据行结构时就提到过,记录的真实数据除了列数据以外,还会为每个记录默认添加一些列(也称为隐藏列),其中有两个就是用于实现 MVCC 的:

  • DB_TRX_ID(transaction_id):事务 id,占 6 字节。当一个事务对某条记录进行改动时,就会把该事务的事务 id 记录在 trx_id 隐藏列里
  • DB_ROLL_PTR(roll_pointer):回滚指针,占 7 字节。每次对某条记录进行改动时,都会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。

Undo Log

MySQL 对数据进行修改操作时,并不是直接覆盖数据,而是通过 undo log 形成一个版本链。关于 undo log 后面在日志部分会进行详细介绍。

在这里插入图片描述

ReadView

ReadView 相当于数据快照。「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 ReadView,而「可重复读」隔离级别是「启动事务时」生成一个 ReadView,然后整个事务期间都在用这个 ReadView。

ReadView 有四个字段:

  • m_ids :指的是在创建 ReadView 时,当前数据库中「活跃事务」的事务 id 列表“活跃事务”指的就是,启动了但还没提交的事务
  • min_trx_id :指的是在创建 ReadView 时,当前数据库中「活跃事务」中事务 id 最小的事务,也就是 m_ids 的最小值。
  • max_trx_id :这个并不是 m_ids 的最大值,而是创建 ReadView 时当前数据库中应该给下一个事务的 id 值,也就是全局事务中最大的事务 id 值 + 1;
  • creator_trx_id :指的是创建该 ReadView 的事务的事务 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 列表中:
    • 如果记录的 trx_id m_ids 列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务不可见
    • 如果记录的 trx_id 不在 m_ids列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务可见

这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫多版本并发控制。

嵌套事务

MySQL 是不支持嵌套事务的,开启了一个事务的情况下,再开启一个事务,会隐式的提交上一个事务。

但是可以用 savepoint 和 rollback to 实现嵌套事务的功能。

示例:

START TRANSACTION;
SAVEPOINT a;
UPDATE `user` SET stock = 1 WHERE id = 1;
SAVEPOINT b;
UPDATE `user` SET stock = 2 WHERE id = 1;
ROLLBACK TO b;
commit;

最后

本文介绍了 MySQL 事务相关的内容,包括常见的并发问题:脏读、不可重复读和幻读,以及四个事务的隔离级别,其中最重要的是 InnoDB 默认的隔离级别:可重复读,在这种隔离级别下,通过 MVCC 极大的避免了快照读时的幻读问题。

下一节将介绍 MySQL 的锁。

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

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

相关文章

如何优化VPS服务器性能,提升网站访问速度?

随着互联网的发展,越来越多的企业开始使用VPS服务器来托管其网站。然而,一些企业经常会遇到网站速度慢、响应时间长等问题,这不仅会影响用户的体验,还会导致客户流失。因此,优化VPS服务器的性能,提升网站访…

好程序员:Java培训班包就业靠谱吗?Java培训机构怎么选?

好程序员本身就是培训机构,现在已经10年多了。说句实在话,包就业的机构几乎没有,凡是给你说包就业的机构大多都不靠谱。你还得看机构的培训能力和就业率,其实能否找到工作还得看你自己在培训班学的怎么样了对吧,找工作…

CIAA 网络安全模型 — TLS v1.3 和 HTTPS 协议

目录 文章目录 目录SSL/TLSTLS 1.21. client_hello2. server_hello server_certificate sever_hello_done3. Certificate authentication4. client_key_exchange change_cipher_spec encrypted_handshake_message5. change_cipher_spec encrypted_handshake_message TLS 1…

portraiture3.5.6免费版PS图片磨皮软件

Portraiture是专注于图像后期处理软件研发的 Imagenomic, LLC重头产品之一,在摄影爱好者中极负盛名。Portraiture 可以将繁琐复杂的人像磨皮操作极致简化,不论是普通爱好者或专业后期处理人员,均能一键完成,被称为人像磨皮神器。 …

1. 跨域学习

1. 跨域学习 1.1 什么是跨域 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同…

最新全网的ChatGPT让AI回答你的任何问题!国内免费用!!

ChatGPT,最近全网最火爆的顶流话题,不管数码爱好者、新闻媒体,还是投资客,无一不在关注着这一牛掰的人工智能项目 它是由OpenAI实验室推出的一款AI工具,拥有极其智能的对话能力,可以回答任何你提出的问题&…

Vuex-状态管理模式

Vuex Vuex 是一个专为 Vue.js 开发的状态管理模式。主要是是做数据交互,父子组件传值可以很容易办到,但是兄弟组件间传值(兄弟组件下又有父子组件),页面多并且一层嵌套一层的传值,非常麻烦,这个…

函数数组的运算

函数数组的运算 一:冒泡运算 类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。 基本思想: 冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前…

D31FBE01EC1NF00PARKER比例方向阀

D31FBE01EC1NF00PARKER比例方向阀是宁波秉圣工业,美国派克比例阀主要具有方向功能,流量功能,压力功能,因此主要有三类:方向阀,流量阀,压力阀,其中方向阀和压力阀直接控制和操作你。被…

一起来!白嫖Amazon DynamoDB!!!

Amazon DynamoDB简介 Amazon DynamoDB是由Amazon Web Services(AWS)提供的一种快速、灵活、全托管的NoSQL数据库服务,支持文档和键/值数据模型。它具有自动扩展、低延迟、高可靠性、高吞吐量等特点,能够处理从几个字节到几TB的数…

tiechui_lesson08_内存的分配和链表

主要是将链表结构的使用,在内核开发中使用起来比较方便的一种数据结构【LIST_ENTRY】。 一、内存的分配 主要是学习一些基本操作。现在推荐使用的动态分配函数【ExAllocatePoolWithTag】 PVOID tempbuffer ExAllocatePoolWithTag(NonPagedPool, 0x1000, xxaa); …

DJ4-6 层次选路

目录 一、层次选路的基本概念 二、域内路由选择 1、RIP* 2、OSPF 三、域间路由选择 BGP 1、AS 互连 2、AS 域间选路任务 3、示例:在 1d 上设置转发表 4、示例:在多个 AS 中做出选择 5、BGP 会话与通告 6、传播可达信息 7、路径属性和 BGP 路…

马蹄集第四期oj

目录 供水管线 黑客小码哥 逆序 来给单词分类 前k小数(进阶) 前K小数 线段树 队列安排 一元多项式的加法 快排变形 供水管线 难度:钻石 0时间限制:1秒 巴占用内存:128M 在个城市之间原本要规划修建许多条下水管道…

提高开发团队能力 这4点很重要

组建开发团队,提高开发团队能力的前提是需要选对人,不仅需与专业匹配,与公司文化相匹配,更与管理者相匹配。 而团队能力的提升需要重点关注:流程化,标准化、工具化和持续赋能。尤其通过流程化、标准化和工具…

TIM输入捕获-STM32

TIM输入捕获-STM32 IC(Input Capture) 输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕…

Unity 自建package包流程

目录 1.在工程Asset 同级目录下创建文件夹 名字随便起 2.在文件夹中添加package.json 文件 3.在unity中选中PackageManager 4.打开vs 新建一个项目 5.开始编写代码 6.修改dll路径 7.打个dll 1.在工程Asset 同级目录下创建文件夹 名字随便起 eg: 2.在文件夹中添加package…

《MySQL 必知必会》课程笔记(三)

怎么创建和修改数据表? 创建和修改数据表,是数据存储过程中的重要⼀环。我们不仅需要把表创建出来,还需要正确地设置限定条件,这样才能确保数据的一致性和完整性。同时,表中的数据会随着业务需求的变化而变化&#xf…

docker ngxin

安装docker环境 官方安装 官方安装 Install Docker Engine on CentOS | Docker Documentation sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repoyum install docker-ce docker-ce-cli container…

在滴滴和字节跳动划水4年,过于真实了...

先简单交代一下吧,沅哥是某不知名211的本硕,18年毕业加入滴滴,之后跳槽到了头条,一直从事测试开发相关的工作。之前没有实习经历,算是四年半的工作经验吧。 这四年半之间他完成了一次晋升,换了一家公司&am…

你有了一套采购系统,就数字化转型了吗?

我觉得完全没有达到,我们觉得要把这个系统要应用起来,用得好才能够说明你这个系统真正地做了数字化转型的。 甄云作为采购数字化服务商,在服务客户时,深有感触。 流程断点,但没有充分采购数字化价值 我这边讲一个故事…