延安市网站建设_网站建设公司_搜索功能_seo优化
2026/1/16 9:27:15 网站建设 项目流程

新手必看:MySQL 事务到底是什么?ACID + 脏读 / 幻读讲明白

一、事务的核心定义

事务(Transaction)是数据库操作的一个不可分割的执行单元,它包含了一系列的数据库操作(比如增删改查),这些操作要么全部成功执行并提交,要么全部失败并回滚,就像一个整体一样,保证了数据的一致性。

可以用一个生活例子理解:你去银行转账(A 账户转 100 元到 B 账户),这个操作包含两步:A 账户扣 100 元、B 账户加 100 元。这两步必须同时成功,才算转账完成;如果其中任意一步失败(比如 B 账户不存在),那么 A 账户扣的钱也必须恢复,这就是事务要解决的问题。

二、事务的四大特性(ACID)

这是事务最核心的特性,也是判断事务是否合规的标准:

特性英文全称含义解释
原子性(A)Atomicity事务中的所有操作要么全做,要么全不做,不存在部分执行的情况。
一致性(C)Consistency事务执行前后,数据库的完整性约束(比如主键唯一、外键关联)保持不变。
隔离性(I)Isolation多个并发执行的事务之间相互隔离,一个事务的执行不能被其他事务干扰。
持久性(D)Durability事务一旦提交成功,其修改的数据会永久保存到数据库中,即使数据库崩溃也不会丢失。

三、MySQL 中事务的使用方式

MySQL 中默认的存储引擎 InnoDB 支持事务(MyISAM 不支持),事务的使用主要分为两种方式:

1. 自动提交(默认模式)

MySQL 默认开启autocommit=ON,即每执行一条 DML 语句(INSERT/UPDATE/DELETE),都会自动作为一个独立的事务提交。

可以通过以下命令查看 / 修改:

-- 查看自动提交状态SELECT@@autocommit;-- 1表示开启,0表示关闭-- 临时关闭自动提交(当前会话有效)SETautocommit=0;
2. 手动控制事务(核心用法)

手动控制事务需要用到三个关键命令:

  • START TRANSACTION/BEGIN:开启事务
  • COMMIT:提交事务(所有操作生效)
  • ROLLBACK:回滚事务(撤销所有未提交的操作)
  • SAVEPOINT:设置保存点,可回滚到指定位置(而非全部)

示例:转账操作的事务实现

-- 1. 开启事务STARTTRANSACTION;-- 2. 执行转账操作(两步)-- A账户扣100元(假设A账户id=1)UPDATEaccountSETbalance=balance-100WHEREid=1;-- B账户加100元(假设B账户id=2)UPDATEaccountSETbalance=balance+100WHEREid=2;-- 3. 检查操作是否正常(可加判断逻辑)-- 如果没问题,提交事务COMMIT;-- 如果有问题(比如B账户不存在),回滚事务-- ROLLBACK;-- (可选)保存点用法STARTTRANSACTION;UPDATEaccountSETbalance=balance-100WHEREid=1;SAVEPOINTsp1;-- 设置保存点UPDATEaccountSETbalance=balance+100WHEREid=2;-- 若第二步出错,只回滚到保存点(A账户的扣款不回滚)ROLLBACKTOsp1;COMMIT;

四、事务的隔离级别

多个事务并发执行时,可能会出现脏读、不可重复读、幻读等问题,MySQL 提供了 4 种隔离级别来解决这些问题,隔离级别越高,数据一致性越好,但并发性能越低。

1. 四种隔离级别(从低到高)
隔离级别英文名称解决的问题
读未提交(Read Uncommitted)READ UNCOMMITTED无(会出现脏读、不可重复读、幻读)
读已提交(Read Committed)READ COMMITTED解决脏读(但仍有不可重复读、幻读),是 Oracle 默认级别
可重复读(Repeatable Read)REPEATABLE READ解决脏读、不可重复读(仍有幻读),是 MySQL InnoDB 默认级别
串行化(Serializable)SERIALIZABLE解决所有问题(但并发性能最差,相当于单线程执行)
2. 隔离级别相关命令
-- 查看当前会话的隔离级别SELECT@@transaction_isolation;-- 查看全局隔离级别SELECT@@global.transaction_isolation;-- 设置当前会话的隔离级别(示例:设置为读已提交)SETSESSIONTRANSACTIONISOLATIONLEVELREADCOMMITTED;-- 设置全局隔离级别SETGLOBALTRANSACTIONISOLATIONLEVELREPEATABLEREAD;
3.什么是脏读、幻读、不可重复读?

我们先统一一个前提场景:数据库中有一张account表,初始数据为id=1, balance=1000,同时有两个并发执行的事务:事务 A(读写操作)、事务 B(写操作)。

脏读(Dirty Read)

定义

脏读是指一个事务读取到了另一个事务尚未提交的修改数据。这些未提交的数据就像 “脏数据”,因为后续另一个事务可能会回滚,导致当前事务读取到的是无效数据。

示例(隔离级别:读未提交 READ UNCOMMITTED)

时间顺序事务 A(读取数据)事务 B(修改数据)
1开启事务开启事务
2-将 id=1 的 balance 改为 2000(未提交)
3读取 id=1 的 balance,得到 2000-
4-发现错误,执行 ROLLBACK 回滚事务
5提交事务-

事务 A 读取到了事务 B 未提交的 2000,但事务 B 最终回滚了,所以事务 A 读取的是 “脏数据”,这就是脏读。

不可重复读(Non-repeatable Read)

定义

不可重复读是指同一个事务内,多次读取同一数据,但得到的结果不一致。原因是在两次读取之间,另一个事务提交了对该数据的修改。

示例(隔离级别:读已提交 READ COMMITTED)

时间顺序事务 A(重复读取)事务 B(修改并提交)
1开启事务-
2读取 id=1 的 balance,得到 1000-
3-开启事务,将 id=1 的 balance 改为 2000,执行 COMMIT 提交
4再次读取 id=1 的 balance,得到 2000-
5提交事务-

事务 A 在同一个事务内两次读取同一数据,结果却不同,这就是不可重复读。它和脏读的区别是:脏读读取的是未提交的数据,不可重复读读取的是已提交的修改数据。

幻读(Phantom Read)

定义

幻读是指同一个事务内,多次执行同一个查询条件的 SQL 语句,查询结果的行数发生了变化。原因是在两次查询之间,另一个事务提交了插入 / 删除操作,导致 “凭空出现” 或 “消失” 了一些符合条件的记录,像幻觉一样。

示例(隔离级别:可重复读 REPEATABLE READ,InnoDB 默认级别可缓解但未完全解决)

时间顺序事务 A(范围查询)事务 B(插入数据并提交)
1开启事务-
2查询 balance>500 的记录,得到 1 条(id=1)-
3-开启事务,插入一条记录:id=2, balance=1500,执行 COMMIT 提交
4再次执行相同查询(balance>500),得到 2 条记录(id=1、id=2)-
5提交事务-

事务 A 在同一个事务内,相同查询条件的结果行数变了,这就是幻读。它和不可重复读的区别是:

不可重复读:针对单条记录的内容修改(update);

幻读:针对记录行数的变化(insert/delete)。

不同隔离级别对三种问题的解决情况

为了更清晰对比,整理成表格:

隔离级别脏读不可重复读幻读
读未提交
读已提交
可重复读(MySQL 默认)基本解决(InnoDB 通过 MVCC 缓解,极端场景仍可能出现)
串行化

简单打个比方:

我们用图书馆借书的场景,把三个问题分析一下:

假设你(事务 A)在图书馆查书、借书,管理员(事务 B)在整理书架、新增 / 修改书籍,二者同时进行。

脏读 → 拿了一本 “待销毁的草稿书”

场景:管理员正在整理一本新书,还没最终定稿(事务 B 未提交),只是临时放在书架上。你刚好路过,拿起这本书看了起来(事务 A 读取未提交数据)。

结果:管理员突然发现这本书内容有误,直接把它销毁了(事务 B 回滚)。你刚才看的内容,相当于 “白看了”,是无效的脏数据。

不可重复读 → 同一本书,两次看内容不一样

场景:你今天专门来图书馆看《MySQL 实战》(开启事务 A),第一次拿起来看,第 100 页写的是 “事务隔离级别”(第一次读取数据)。

过程:你中途去接水,管理员路过书架,发现这本书第 100 页印错了,当场修正并更新了馆藏记录(事务 B 修改并提交)。

结果:你回来继续看同一本书,第 100 页变成了 “ACID 四大特性”(同一事务内重复读取,内容不同)。

幻读 → 找同一类书,数量凭空变多 / 变少

场景:你要找 “所有 MySQL 相关的书”(开启事务 A),第一次统计书架上只有 3 本(范围查询结果)。

过程:你转身去登记,管理员搬来一箱新书,全是 MySQL 系列,直接上架并录入系统(事务 B 插入数据并提交)。

结果:你回来再统计一次 “所有 MySQL 相关的书”,变成了 8 本(同一事务内相同查询条件,行数变了)。就像出现了幻觉,凭空多了 5 本。

脏读:读了其他事务未提交的 “脏数据”,是最严重的读取问题;也就是读的是别人没最终确认的无效数据;

不可重复读:同一事务内多次读同一行,内容被其他事务修改并提交,核心是 “行内容变了”;也就是同一行数据被改了;

幻读:同一事务内多次读同一范围,行数被其他事务增删并提交,核心是 “行数变了”;也就是符合条件的行数被增删了。

隔离级别越高,越能解决这些问题,但数据库并发性能会越低,实际开发中需根据业务平衡一致性和性能。

五、事务的使用注意事项

只有 InnoDB 存储引擎支持事务,MyISAM 不支持,使用时需确认表的存储引擎;

事务主要用于 DML 操作(INSERT/UPDATE/DELETE),DDL 操作(CREATE/DROP/ALTER)会自动提交事务,无法回滚;

事务开启后,若长时间不提交 / 回滚,会占用数据库连接和锁资源,影响性能;

尽量缩小事务的执行范围,避免在事务中执行耗时操作(比如远程调用、复杂计算)。

总结

事务是 MySQL 中保证数据一致性的核心机制,核心特性是 ACID(原子性、一致性、隔离性、持久性);

InnoDB 支持事务,常用START TRANSACTION开启、COMMIT提交、ROLLBACK回滚来手动控制;

MySQL 默认隔离级别是可重复读(Repeatable Read),可根据业务需求调整,隔离级别越高并发性能越低。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询