当前位置: 首页 > news >正文

Mysql数据库事务全解析:概念、操作与隔离级别

MySQL系列


文章目录

  • MySQL系列
  • 一、什么是事务
    • 1.1事务的核心概念
    • 1.2、 事务的四大属性(ACID)
      • 1.2.1 原子性(Atomicity)
      • 1.2.2 一致性(Consistency)
      • 1.2.3 隔离性(Isolation)
      • 1.2.4 持久性(Durability)
    • 1.3 为什么会出现事务
    • 1.5 事务的版本支持
  • 二、事务操作
    • 2.1 事务的提交
    • 2.2 事务的基本操作
    • 2.3 单挑sql和事务的关系
  • 三、事务隔离级别
    • 3.1 隔离级别
    • 3.2 隔离级别的操作
      • 3.2.1查看隔离级别
      • 3.2.2 设置隔级别
  • 四、隔离级别的具体表现
    • 4.1 读未提交
    • 4.2 读提交
    • 4.3 可重复读
    • 4.4 串行化
    • 4.5 总结


上一篇:MySQL 索引:结构、对比与操作实践指南

一、什么是事务

1.1事务的核心概念

事务是数据库操作中的核心概念,其核心定义可概括为:
由一组DML语句(数据操纵语言,如INSERT、UPDATE、DELETE等)组成,这些语句在逻辑上存在紧密相关性(例如完成一次转账需同时涉及转出账户扣款和转入账户收款)。
作为一个不可分割的整体,这组DML语句遵循要么全部成功执行,要么全部失败的原则——只要其中任一语句执行出错,所有已执行的操作都会被撤销。
此外,事务确保:不同客户端在操作过程中,看到的数据状态可能是不相同的,以此避免并发操作导致的数据混乱。

一个事务不仅仅只是简单的sql集合,同时满足如下四个属性

1.2、 事务的四大属性(ACID)

这里先简单了解,后面的内容,会围绕这四大特定详细介绍
在这里插入图片描述
MySQL做为网络服务器一定会存在并发访问的场景,而这就可能发生图中错误,要想解决这个问题,就需要保证:
1.买票的过程得是原子
2. 买票互相不能影响
3. 买完票要永久有效
4. 买前,和买后都要是确定的状态

为了解决这个问题,MySQL对事务做了如下要求:

1.2.1 原子性(Atomicity)

事务(transaction)里的所有操作是一个不可分割的整体,要么全部成功执行,要么全部回滚撤销 。若执行中出现错误,会回滚(Rollback)到事务开始前状态,如同事务从未执行过,保障操作的“一荣俱荣,一损俱损”。

1.2.2 一致性(Consistency)

事务执行前和执行后,数据库的完整性(如数据精度、关联性等规则)不会被破坏 。写入的数据必须严格符合预设规则,确保数据库能按预期提供服务,维持数据的安全可靠。

1.2.3 隔离性(Isolation)

数据库支持多个事务并发读写、修改数据,且能通过隔离性避免因事务交叉执行导致数据混乱 。隔离性有不同级别,常见的有:读未提交(Read Uncommitted )、读提交(Read Committed )、可重复读(Repeatable Read )、串行化(Serializable ),不同级别平衡并发效率与数据一致性。

1.2.4 持久性(Durability)

事务成功提交后,对数据的修改会永久留存 ,即便系统故障(如断电、崩溃),修改也不会丢失,保障数据最终的“稳定落地”。

这四大属性的英文首字母缩写为 ACID ,是事务机制的核心保障。

1.3 为什么会出现事务

MySQL中事务的设计,本质是为应用程序访问数据库时提供便利——它能极大简化编程模型,让开发者无需手动处理各种潜在错误与并发问题。

试想,若没有事务机制,编写数据库访问程序时,需额外考虑的问题会极为繁琐:比如网络突然中断如何处理?服务器意外宕机后数据如何恢复?多个操作同时修改同一份数据时如何避免冲突?…… 而有了事务,开发者只需关注“提交(Commit)”或“回滚(Rollback)”两种操作即可,上述复杂场景都由事务机制自动处理。

由此可见,事务并非数据库系统与生俱来的组件,而是专为服务应用层而设计的工具,其核心价值在于降低应用程序与数据库交互时的开发复杂度。

1.5 事务的版本支持

show engines;

在这里插入图片描述
可以看到并不是所有的引擎都支持事务。

二、事务操作

2.1 事务的提交

事务的提交方式常见的有两种:

  • 自动提交
  • 手动提交

查看是否的提交方式:

show variables like 'autocommit';

在这里插入图片描述
可以看到默认情况下是打开的;

更改自动提交:

// 禁止自动提交:
SET AUTOCOMMIT=0;

在这里插入图片描述

// 开启自动提交:
SET AUTOCOMMIT=1;

在这里插入图片描述
两者的具体区别后面会做验证

2.2 事务的基本操作

接下来我会营造并发场景展开介绍

准备工作:
为了便于演示,先将mysql的默认隔离级别设置成读未提交

set global transaction isolation level READ UNCOMMITTED;

重启终端(也可以重新登录MySQL),进行查看隔离级别

select @@transaction_isolation;

在这里插入图片描述
创建测试表

create table if not exists account(
id int primary key,
name varchar(50) not null default '',
blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;

启动事务(两种方法):

  • start transaction;
  • begin
    设置保存点(标记,方便回滚)
  • savepoint 保存点名

在这里插入图片描述
可以看到我们在read uncommitted级别的隔离下,并发操作一整表时,事务发起者向表中插入后不需要等到事务提交,并发参与者立马可以看到,事务发起者在执行操作时也可以边操作边插入保存点,可以通过rollback to 保存点名回滚到设置保存点前的状态(若为设置保存点,可以直接使用rollback直接回滚到事务开始状态),此时若我们的操作失败、服务器奔溃,就会自动回滚到,执行事务前的状态。
在这里插入图片描述
可以看到事务发起者异常退出时,事务就会回滚到开始前状态,数据不会被持久化,采用这种事务的形式,就实现了原子化的概念。
有很多场景在这里不可能全部演示,你可以自己尝试,使用ctrl+\可以模拟服务退出
commit提交事务
当我们提交事务后,数据就会永久保存,再次回滚就不会回到之前了
在这里插入图片描述
只要事务发起者commit后数据机会持久化,即使再次回滚数据依然保存。

我们不是开启自动提交了吗?我什么异常退出后,事务无法自动提交呢?
MySQL要求,手动发起的事务,必须要手动提交,而自动提交是帮助默认发起的事务做提交的,下面我们来验证一下。

2.3 单挑sql和事务的关系

关闭自动提交 set autocommit=0
在这里插入图片描述
可以看到,当关闭自动提交后,事务发起者向表中插入数据时,若MySQL服务异常退出,数据会回滚到之前状态。这是因为在MySQL中,单条SQL语句默认也会被当作事务处理,其提交依赖自动提交功能。当关闭自动提交后,即便执行单条SQL(本质也是事务范畴),因未手动提交,异常退出时就无法完成提交,最终触发回滚 。
相反的,在正常情况下,自动提交方法是打开的,那么即使mysql崩溃了,它数据也是会自动提交成功的(所以执行的所有sql本质都是事务!!只不过进行了自动提交)。

总结

  1. 只要输入 begin 或者 start transaction,事务便必须要通过 commit 提交,才会持久化,与是否设置 set autocommit 无关。
  2. 事务可以 手动回滚,同时,当操作异常,MySQL 会 自动回滚
  3. 对于 InnoDB,每一条 SQL 语言都默认封装成事务,自动提交select 有特殊情况,因为 MySQL 有 MVCC)。
  4. 从上面的例子,我们能看到事务本身的 原子性(回滚),持久性(commit)。
  5. 如果没有设置 保存点,也可以回滚,只能回滚到事务的开始,直接使用 rollback(前提是事务还没有提交)。
  6. 如果一个事务被 提交了(commit),则 不可以回退(rollback)
  7. 可以选择回退到 哪个保存点
  8. InnoDB 支持事务MyISAM 不支持事务
  9. 开始事务可以使用 start transaction 或者 begin

三、事务隔离级别

首先需要明确:MySQL服务作为网络服务器,可能同时被多个客户端进程(线程)访问,且访问以事务形式进行。一个事务可能包含多条SQL,因此任何事务都存在三个阶段:

  • 执行前
  • 执行中
  • 执行后

原子性的核心,是让用户层要么看到事务执行前的状态,要么看到执行后的状态。若执行中出现问题,可随时通过回滚撤销操作。因此,单个事务对用户呈现的核心特性就是原子性

但需注意:所有事务都有执行过程,当多个事务并发执行多条SQL时,仍可能出现互相影响——例如,多个事务同时访问同一张表甚至同一行数据
而有些情况不会对操作造成影响(如:并发读取数据),有些情况则会导致结果出错(如:一端删除、一端查找可能引发执行错误)。

  • 因此,数据库中为保证事务执行过程尽量不受干扰,存在一个重要特征:隔离性
  • 同时,数据库允许事务受不同程度的干扰,由此衍生出另一种重要特征:隔离级别

3.1 隔离级别

读未提交(Read Uncommitted)

  • 核心特征:所有事务可看到其他事务未提交的执行结果
  • 问题:相当于无隔离性,会引发脏读、幻读、不可重复读等所有并发问题。 (上面的测试就是使用的这个隔离级别)

读提交(Read Committed)

  • 核心特征:事务仅能看到其他事务已提交的修改(满足隔离性的基础定义)。
  • 问题:会导致不可重复读(同一事务中多次 select 可能得到不同结果)。
  • 默认情况:是大多数数据库的默认隔离级别(非 MySQL 默认)。

可重复读(Repeatable Read)

  • 核心特征:确保同一事务中,多次读取数据时看到的数据行一致
  • 问题:仍可能存在幻读
  • 默认情况MySQL 的默认隔离级别

串行化(Serializable)

  • 核心特征:事务的最高隔离级别,通过强制事务排序避免冲突,解决幻读问题(原理是对读取的数据行加共享锁)。
  • 问题:可能导致超时和锁竞争,性能极低。
  • 使用场景:实际生产中基本不使用(隔离级别过于严格)。

3.2 隔离级别的操作

3.2.1查看隔离级别

查看全局隔离级别

select @@global.transaction_isolation;

在这里插入图片描述
查看当前会话隔离级别

select @@session.transaction_isolation;
select @@transaction_isolation;

在这里插入图片描述

3.2.2 设置隔级别

设置当前会话 or 全局隔离级别语法:

set [ session | global ] transaction isolation level { read uncommitted | read committed | repeatable read | serializable}

设置当前会话的隔离级别

set session transaction isolation level read committed;

在这里插入图片描述
设置全局的隔离级别

set global transaction isolation level serializable;

在这里插入图片描述
可以看到全局隔离级别的改变,不会对以创建的会话产生作用,而他的作用是设置新建的会话。
也就是说重启mysql后就会变成全局的隔离级别

四、隔离级别的具体表现

4.1 读未提交

读未提交:几乎不施加锁机制,虽执行效率高,但存在严重问题

其核心问题是脏读(dirty read):一个事务在执行过程中,能读到另一个未提交事务的更新(或其他操作)—— 因为事务执行有过程性,只要一个用户修改了表,即便未执行 commit,其他用户无需等待提交就能立即看到这些未确认的操作

这正是“读未提交”的本质:事务只要执行了SQL(未提交),其对表的操作就会被其他事务可见
在这里插入图片描述

脏读具体来说:

  1. 事务A(发起者) 对数据做了修改(如更新某条记录),但尚未执行 commit(可能处于执行中或未完成);
  2. 事务B(并发者) 在自己的事务中读取到了事务A未提交的修改结果;
  3. 若事务A因异常(如代码错误、数据库崩溃等)发生回滚,其修改会被撤销,数据恢复到初始状态;
  4. 此时事务B之前读取到的“未提交数据”就成了无效的错误数据,基于该数据的后续操作(如计算、决策、更新)也会随之出错。

这种“读到临时且可能被回滚的数据”的现象,正是脏读。

4.2 读提交

为方便截取我先把表清空
在这里插入图片描述
在读提交隔离级别中:

  • 事务发起者未提交时,事务并发者看不到其操作
  • 一旦发起者执行 commit 提交,即使并发者的事务未结束,也会立即看到提交后的修改。

这会导致 不可重复读(non-repeatable read) 问题:同一事务内,相同的读取操作在不同时间点(事务仍在执行中)返回不同结果

从逻辑上,一个事务提交后其他事务能看到最新数据是合理的,但站在并发事务的一致性角度,同一事务内多次读取应保持一致,否则会破坏事务内数据的稳定性——这正是不可重复读的问题核心。

示例

  1. 事务A(并发者)启动,读取到 account 表中 id=1 的余额为 1000 元。
  2. 事务B(发起者)启动,将 id=1 的余额改为 2000 元并提交。
  3. 事务A未结束,再次读取 id=1 的余额,结果变为 2000 元——同一事务内两次读取结果不同,即不可重复读。

4.3 可重复读

可重复度是MySQL的默认隔离级别
在这里插入图片描述
可重复读(MySQL 默认隔离级别)的核心特性是:同一事务在执行期间,多次读取数据会保持一致,直到自身事务提交后,才能看到其他事务的修改结果。

例如:终端A在事务中执行 INSERT 操作,终端B在自身事务周期内多次查看,均不受终端A未提交或已提交数据的影响,这符合可重复读的特点。

但多数数据库的可重复读存在一个问题:无法屏蔽其他事务新插入(INSERT)的数据

原因在于:隔离性通常通过对已存在数据加锁实现,而待插入的数据因尚未存在,无法被传统锁机制覆盖。因此,同一事务内多次查询时,可能会读到其他事务新插入的记录,出现“多次查找结果不一致、新增了未预期的记录”的现象,这被称为 幻读(phantom read)

关键差异:MySQL 的可重复读(RR 级别)通过 Next-Key 锁(间隙锁 + 行锁) 解决了幻读问题——不仅锁定已有数据行,还锁定数据间隙,防止其他事务在间隙中插入新记录,从而保证事务内读取结果的稳定性。

4.4 串行化

前面三个隔离级别主要特点是:一方在修改数据(CUD操作),一方在读取数据(R操作),但是面对双方都在修改数据的场景(CUD操作),我们就必须通过加锁来实现了

对所有事务操作全部加锁,进行事务的串行化,但是只要串行化,效率很低,几乎完全不会被采用。
在这里插入图片描述
可以看到在串行化隔离级别下,并发的事务查询并不会受到锁的约束,但如果想要对数据做修改,sql就会被阻塞(阻塞时间过长就会报错)。
在这里插入图片描述
当有一方提交事务后,锁就会被释放,阻塞的sql就会再次执行。

4.5 总结

隔离级别越严格,数据安全性越高,但数据库并发性能越低,实际应用中需在两者间寻找平衡。

  • 不可重复读的重点是修改和删除:同一条件下,两次读取同一数据,结果值不同。
  • 幻读的重点是新增:同一条件下,两次读取的记录数量不同。

从实例中可看出,事务存在长事务、短事务的概念。事务间的互相影响,在并行执行且均未提交时尤为显著。
在这里插入图片描述

一致性(Consistency)

  • 核心定义:事务执行结果必须使数据库从一个一致性状态切换到另一个一致性状态。当数据库仅包含所有成功提交事务的结果时,处于一致性状态;若因系统中断导致未完成事务的修改写入数据库,则数据库会处于不一致状态

  • 保障关系:一致性通过原子性(事务要么全成、要么全滚)提供基础保障。

  • 技术支撑:从技术层面,一致性(C)通过原子性(A)、隔离性(I)、持久性(D) 共同保障(即 ACID 中的 AID 支撑 C)。


后面这篇文章是对隔离性更深层次的介绍


文章转载自:

http://9gZLUQZl.tjkth.cn
http://4Wan1AbK.tjkth.cn
http://K3bwFFD3.tjkth.cn
http://bTmUswn9.tjkth.cn
http://IoPh3uIz.tjkth.cn
http://v26rJITX.tjkth.cn
http://5GaJWgJr.tjkth.cn
http://4MscE399.tjkth.cn
http://AFZobLUP.tjkth.cn
http://Md59zEMC.tjkth.cn
http://JQLV2jvs.tjkth.cn
http://4SOjVn55.tjkth.cn
http://llN07kGn.tjkth.cn
http://jlj6dEhf.tjkth.cn
http://bsOwZBPT.tjkth.cn
http://rEZvQFig.tjkth.cn
http://1H4mJ2Di.tjkth.cn
http://o8x6WkvW.tjkth.cn
http://A6RXp8Vz.tjkth.cn
http://quCJwoiQ.tjkth.cn
http://DH1QHnGq.tjkth.cn
http://XDCvfCzV.tjkth.cn
http://yk6OyDhD.tjkth.cn
http://g8EGSRSB.tjkth.cn
http://UOqkywpU.tjkth.cn
http://5alhzhYh.tjkth.cn
http://KydeWext.tjkth.cn
http://3iLLXm3w.tjkth.cn
http://hb8qiI8a.tjkth.cn
http://YrZmOQRh.tjkth.cn
http://www.dtcms.com/a/384401.html

相关文章:

  • Halcon 常用算子
  • 基于Spring Boot与Micrometer的系统参数监控指南
  • 【高并发内存池——项目】定长内存池——开胃小菜
  • 作为注册中心zk和nacos如何选型
  • 前置配置3:nacos 配置中心
  • Linux —— 进程的程序替换[进程控制]
  • [Linux] 从YT8531SH出发看Linux网络PHY驱动
  • ArcGIS定向影像(2)——非传统影像轻量级解决方案
  • 分享机械键盘MCU解决方案
  • Unity 性能优化 之 编辑器创建资源优化(UGUI | 物理 | 动画)
  • PostgreSQL——分区表
  • Elastic APM 高级特性:分布式追踪与机器学习优化
  • Ubuntu 服务器配置转发网络访问
  • Redis 数据结构源码剖析(SDS、Dict、Skiplist、Quicklist、Ziplist)
  • C#通讯之网络通讯 TCP UDP
  • 响应时间从5ms到0.8ms:威迈斯AI+DSP协同架构的突破与工程实践
  • 《WINDOWS 环境下32位汇编语言程序设计》第16章 WinSock接口和网络编程(2)
  • 算法--插入排序
  • 领码方案|权限即数据:企业系统中的字段级访问控制架构实战(Ver=1.0)
  • 【面试场景题】支付金融系统与普通业务系统的一些技术和架构上的区别
  • 数证杯顺心借JAVA网站重构详细版(服务器取证基础考点+检材+题目+重构视频)
  • 【Unity】【Photon】Fusion2中的玩家输入系统 学习笔记
  • Vue3 + Three.js 实战:自定义 3D 模型加载与交互全流程
  • 【Leetcode hot 100】102.二叉树的层序遍历
  • [Windows] 微软 .Net 运行库离线安装包 | Microsoft .Net Packages AIO_v09.09.25
  • java通过RESTful API实现两个项目之间相互传输数据
  • C++基础(13)——list类的模拟实现
  • C#/.NET/.NET Core技术前沿周刊 | 第 54 期(2025年9.8-9.14)
  • 快速上手 Jenkins
  • 【C++】STL--List使用及其模拟实现