MySQL事务与事务原理

目录

事务

事务的四大特性ACID

事务隔离级别

事务原理

存储引擎

四大特性的保证

MVCC

事务链

ReadView


事务

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

start transaction; -- 开启事务 或者 begin 开启
...
rollback/commit; -- 回滚(全部失败)/提交(全部成功)

事务的四大特性ACID

  • 原子性:事务中的操作要么全部成功,要么全部失败
  • 一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态
  • 隔离性:多个并发事务之间要相互隔离
  • 持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的

事务日志用于保存对数据的更新操作

事务隔离级别

事务隔离级别分为读未提交、读已提交、可重复读、串行化四个级别。

隔离级别

脏读

不可重复读

幻读

读未提交

可能出现

可能出现

可能出现

读已提交

不会出现

可能出现

可能出现

可重复读

不会出现

不会出现

可能出现

串行化

不会出现

不会出现

不会出现

  • 脏读:指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了不一定最终存在的数据,这就是脏读。
  • 可重复读:指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对数据更新(修改或删除)操作。
  • 不可重复读:对比可重复读,不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对数据更新(修改或删除)操作。
  • 幻读:幻读是针对数据插入操作来说的。幻读官方定义,在一个事务中,前后两次使用了相同的查询语句,但是第二次查询发现了第一次查询时不存在的数据(中间没有插入操作),这种查询到了此前未存在的数据就是幻读。

个人看法:按照可重复读隔离级别的定义,在一个事务中,相同的DQL语句查询出来的结果应该保持一致,而可重复读的隔离级别解决不了幻读问题。

然而按照官方的定义,在可重复读的隔离级别下是不应该出现所谓幻读的。

另一种流传较为广泛的定义是:假设事务A开启后,还未提交,此时事务B插入了新的数据,并且提交,而这时,事务A也想插入事务B刚刚插入的数据,但是却插不进去(主键唯一),然而查询却查不到这条数据(这是因为可重复读的隔离级别),让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读。

至于怎么理解,只能见仁见智。

事务原理

在解释原理之前,有必要先了解一下存储引擎。

存储引擎

存储引擎是数据库的核心组件,决定了数据的存储方式、索引构建、并发控制、事务处理、恢复机制及性能优化等关键特性。事实上,不是所有的存储引擎都支持事务,而支持事务的存储引擎,其事务原理也不相同。

常用的存储引擎主要有InnoDB、MyISAM、Memory,各自特点如下:

存储引擎

事务

锁类型

外键

索引

持久化

使用场景

InnoDB

支持

行锁

支持

B+树索引

可持久化

大多数场景

MyISAM

不支持

表锁

不支持

B+树索引

可持久化

性能优先级 > 数据安全的场景

(例如查询评论)

Memory

不支持

表锁

不支持

B+树索引和Hash索引

不可持久化

适用于临时存储,性能高的场景

(作为缓存)

自从MySQL5.5版本开始,默认存储引擎使用InnoDB。因此这里的事务原理是针对InnoDB引擎而言。

四大特性的保证

  • 原子性
    • 通过回滚日志(undolog)保证原子性(undolog日志不止用于回滚操作,在MVCC中也发挥重要作用)。
    • 在事务开始时, InnoDB 会将事务涉及的所有修改操作记录到 undolog 中(逻辑记录,比如要删除一条数据,可能日志中记录的就是新增一条数据)。如果事务执行出错,就可以通过 undolog 实现回滚机制,从而保证了事务的原子性。
  • 一致性
    • 预提交校验(Pre-commit Checks):在事务提交前,MySQL会对事务执行的结果进行校验,确保其符合数据库定义的完整性约束条件。如果违反了约束,则事务会被回滚。
    • 另外需要开发人员通过设置触发器和约束、设定合适的隔离级别以及在业务中处理。
  • 隔离性
    • 通过锁机制和MVCC共同实现。MVCC机制实现读已提交和可重复读,间隙锁和临键锁用来解决幻读问题。
    • 在可重复读隔离级别下,InnoDB不仅锁定查询行,同时会锁定上一行到查询行以及查询行到下一行的间隙,以防止其他事务在此间隙插入新行导致幻读(这里的幻读应该按照官方定义理解)。

举个例子:

假如有这样一组数据:

我要查询age=22的数据,此时age=12的数据到age=24的数据之间都会锁定,共享锁锁定age=22的数据,间隙锁锁定12-22和22-24的数据(不包括12和24)。

此时其他事务想要插入age=18,由于间隙锁的存在,插入操作被阻塞,直到事务提交或回滚会才会执行。

  • 持久性
    • 通过重做日志 (redolog) 保证持久性。
    • 缓冲池往磁盘中的刷新是间歇性的(减少磁盘IO以提升性能),如果刷新失败持久性就会失效。而为了保证性能,又不好每次都往磁盘中写(写操作是相对随机的,性能较低),于是把操作写入 redolog 日志,从 redolog 中往磁盘中同步( redolog 的写入是顺序写入的,效率很高)。

MVCC

MVCC全称是多版本并发控制 (Multi-Version Concurrency Control),只有在InnoDB引擎下存在。MVCC机制的作用其实就是避免同一个数据在不同事务之间的竞争,提高系统的并发性能。

特点

  • 允许多个版本同时存在,并发执行。
  • 读操作不依赖锁机制,性能高。
  • 只在读已提交和可重复读的事务隔离级别下工作。

使用MVCC可以避免读写并发执行时的阻塞,优化了MySQL的并发性能。

MVCC中,读操作是基于"快照"(ReadView) 实现的,可以理解为创建了一个该时刻数据库中数据的副本,读操作是读取的这个副本而非数据库。

事务链

InnoDB引擎中,每张表中包含一些隐藏列

  • trx_id: 事务Id,每当事务对某行数据进行修改时,都会把该事务id赋值给 trx_id,用于记录当前修改操作;
  • roll_pointer: 回滚指针,指向undolog中的某个位置,用于记录上一个版本的数据状态,方便查询历史版本或回滚。
  • db_row_id: 对于没有显式主键的表,InnoDB会自动为其生成一个隐藏的行ID列,作为内部的唯一标识符。

每次对事物中某条数据进行修改时,都会产生一条undolog日志(如果是 insert 操作则不产生),同时roll_pointer会指向这块空间,以便于回滚。

而指针会把多条undolog日志串联起来,形成事务链:

ReadView

InnoDB的 ReadView 就是通过这种版本控制的手段实现读已提交(RC)可重复读(RR)的,在RC隔离级别下,每次查询都会生成一个ReadView,然后根据一定的规则判断哪些事务可见,那些不可见。

ReadView包含四个核心字段:

  • 创建ReadView的事务的id:creator_trx_id
  • 最早的活跃事务(最早开启的还未提交的事务)id:min_trx_id
  • 下一次开启事务预生成的事务id:max_trx_id
  • 所有的活跃事务id列表:m_ids

假设当前所处事务的id为cur_trx_id,则规则如下:

  • cur_trx_id == creator_trx_id (说明修改操作位于当前事务)可以被访问
  • cur_trx_id < min_trx_id (说明当前事务已提交)可以被访问
  • cur_trx_id >= max_trx_id(当前事务在查询之后开启)不可以被访问
  • min_trx_id <= cur_trx_id < max_trx_id 且 cur_trx_id 不在 trx_ids 中(说明当前事务已提交)可以被访问

举例,对于这样一组事务:

此时事务链为:

  1. 第一次生成ReadView的属性为:create_trx_id = 4, min_trx_id = 2, max_trx_id = 5, trx_ids = [2, 3, 4]
  2. 首先是cur_trx_id = 2,显然四个条件都不满足,沿着事务链往下走,cur_trx_id = 3,仍然不满足;
  3. 继续,cur_trx_id = 1,满足第二个条件 cur_trx_id < min_trx_id,可以读取到该版本,即返回的数据为:id = 1, name = 'zang', age = 16

对比前面的图会发现,读取到的数据就是已提交的数据,因此就实现了读已提交;

在RC隔离级别下,每次查询都会生成一个新的ReadView,第二次查询生成的ReadView属性为:create_trx_id = 4, min_trx_id = 2, max_trx_id = 5, trx_ids = [2, 4]

沿着事务链最后读取到的数据为:id = 1, name = 'wang', age = 16。

而在RR隔离级别下,只有在第一次查询才生成ReadView,后续在同一事务中的相同查询语句直接引用已有的ReadView,从而实现可重复读机制。

注意:如果开启事务A后,事务B修改了数据并且提交,此时在事务A中查询,是可以查询到事务B提交的数据的,但只有第一次查询是读已提交(此后即使有其他的事务修改数据并且提交,在事务A中都是查不到的)。

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

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

相关文章

【CDN(Content Delivery Network)】

文章目录 CDN&#xff08;Content Delivery Network&#xff09;视频流化服务和CDN&#xff1a;上下文多媒体: 视频存储视频的流化服务&#xff1a;多媒体流化服务&#xff1a;DASH流式多媒体技术3: DASH CDN&#xff08;Content Delivery Network&#xff09; 视频流化服务和…

kafka学习记录

文章目录 windows单机版kafka搭建步骤主题的增删改查操作消息的生产与消费 Windows集群版kafka搭建步骤 prettyZoo 尚硅谷Kafka教程&#xff0c;2024新版kafka视频&#xff0c;零基础入门到实战 【尚硅谷】Kafka3.x教程&#xff08;从入门到调优&#xff0c;深入全面&#xff0…

Electron+React 搭建桌面应用

创建应用程序 创建 Electron 应用 使用 Webpack 创建新的 Electron 应用程序&#xff1a; npm init electron-applatest my-new-app -- --templatewebpack 启动应用 npm start 设置 Webpack 配置 添加依赖包&#xff0c;确保可以正确使用 JSX 和其他 React 功能&#xff…

flask后端+网页前端:基于 socket.io 的双向通信和服务器部署

我想实现的效果是&#xff0c;我的服务器提供两个路由网址&#xff0c;网页A用于拍照、然后录音&#xff0c;把照片和录音传给服务器&#xff0c;服务器发射信号&#xff0c;通知另一个路由的网页B更新&#xff0c;把刚刚传来的照片和录音显示在网页上。 然后网页B用户根据这个…

每日一题(leetcode238):除自身以外数组的乘积--前缀和

不进阶是创建两个数组&#xff1a; class Solution { public:vector<int> productExceptSelf(vector<int>& nums) {int nnums.size();vector<int> left(n);vector<int> right(n);int mul1;for(int i0;i<n;i){mul*nums[i];left[i]mul;}mul1;for…

7 种实现 CSS 三角形的原理与方法 以及 三角形在网页设计中的作用

三角形在网页设计中不仅是图形设计的基本元素&#xff0c;更是实现视觉引导、空间构建、情绪传达、品牌塑造、性能优化以及创新表达的重要工具。其广泛应用和多功能性使其成为设计师手中不可或缺的设计语言组成部分。本文介绍了7种CSS实现三角形的方法。 CSS实现三角形主要有以…

Gradle 实战 - 命令行传递-ApiHug准备-工具篇-013

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace ApiHug …

VIO第7讲:VINS初始化与VINS系统

VIO第7讲&#xff1a;VINS初始化与VINS系统 文章目录 VIO第7讲&#xff1a;VINS初始化与VINS系统1 VINS初始化1.1 视觉初始化1.1.1 relativePose1.1.2 GlobalSFM与BA优化1.1.3 visualInitialAlign 1.2 VisualIMUAlignment1.2.1 视觉和IMU之间的联系1.2.2 视觉IMU对齐流程① 旋转…

【C++庖丁解牛】底层为红黑树结构的关联式容器--哈希容器(unordered_map和unordered_set)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. unordered系列关联式容…

风电机组中仍然装有电动机吗?

风电机组中确实装有电动机。虽然风电机组的主要功能是将风能转换为电能&#xff0c;但在其启动和运行过程中&#xff0c;电动机发挥着不可或缺的作用。 在风电机组的启动阶段&#xff0c;电动机负责提供初始的启动动力。由于风力发电的特性&#xff0c;风电机组并不能在任意风…

乐趣Python——文件与数据:挥别乱糟糟的桌面

各位朋友们&#xff0c;今天我们要开启一场非凡的冒险——进入文件操作的世界&#xff01;你知道吗&#xff0c;在你的电脑里&#xff0c;有一个叫做“文件系统”的迷宫&#xff0c;里面藏着各种各样的文件和文件夹&#xff0c;它们就像是迷宫中的宝藏。但有时候&#xff0c;这…

C# WebSoket服务器

WebSocket是一种在单个TCP连接上进行全双工通信的协议WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单, 允许服务端主动向客户端推送数据。在WebSocket API中, 浏览器和服务器只需要完成一次握手, 两者之间就直接可以创建持久性的连…

修复 Windows 上的 PyTorch 1.1 github 模型加载权限错误

问题: 在 Windows 计算机上执行示例 github 模型加载时,生成了 master.zip 文件的权限错误(请参阅下面的错误堆栈跟踪)。 错误堆栈跟踪: 在[4]中:en2de = torch.hub.load(pytorch/fairseq, transformer.wmt16.en-de, tokenizer=moses, bpe=subword_nmt) 下载:“https://…

spring Task 定时任务

导入maven坐标 spring-context&#xff08;已存在&#xff09; <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.34</version> <!-- 请根据需要选择合适的版本 -->…

高质量数据赋能大模型应用落地,景联文科技提供海量AI大模型数据

随着人工智能技术的迅猛进步&#xff0c;AI算法持续创新突破&#xff0c;模型的复杂度不断攀升&#xff0c;呈现出爆炸性的增长态势。数据的重要性愈发凸显&#xff0c;已然成为AI大模型竞争的核心要素。 Dimensional Research的全球调研报告显示&#xff0c;72%的受访者认为&a…

【vim 学习系列文章 20 -- a:mode 的值有哪些?】

请阅读【嵌入式开发学习必备专栏 之 Vim】 文章目录 a:mode 的值有哪些?举例Vim 底部状态栏设置 a:mode 的值有哪些? 在 Vim 脚本语言中&#xff0c;a:mode 常常用于函数内部&#xff0c;以获取该函数被调用时 Vim 正处于的模式。它主常用于那些可以从不同模式下被调用的函数…

系统架构最佳实践 -- 构建高效教学平台系统

随着在线教育的迅速发展&#xff0c;教学平台系统成为了教育行业不可或缺的一部分。本文将总结构建高效教学平台系统的关键要素&#xff0c;并介绍最佳实践&#xff0c;以帮助教育机构和企业打造具有竞争力的教学平台系统。 引言&#xff1a; 随着信息技术的不断进步和普及&…

CMake 学习笔记2

其他很好的总结 CMake教程系列-01-最小配置示例 - 知乎 CMake 保姆级教程&#xff08;上&#xff09; | 爱编程的大丙 10-补充(完结)_哔哩哔哩_bilibili 1、基本关键字 SET命令的补充 &#xff08;1&#xff09;SET命令设置执行标准 #增加-stdc11 set(CMAKE_CXX_STANDARD…

如何使用Docker部署Django项目?

第一步&#xff1a;创建Dockerfile文件 在django项目的根目录中创建一个名为Dockerfile的文件&#xff0c;并写入如下配置&#xff1a; # 使用 Python 3.12 作为基础镜像 FROM python:3.12# 设置工作目录 WORKDIR /app# 复制项目文件到工作目录 COPY . /app# 设置清华 pip 镜…

LeetCode 1 in Python. Two Sum (两数之和)

两数之和算法思想很简单&#xff0c;即找到nums[i]和nums[j]target-(nums[i])返回[I, j ]即可。问题在于&#xff0c;简单的两层遍历循环时间复杂度为O()&#xff0c;而通过构建一个hash表就可将时间复杂度降至O(n)。本文给出两种方法的代码实现。 示例&#xff1a; 图1 两数之…