📄 MySQL 🟢 入门 ⏱ 10 分钟

🗄️ MySQL 事务 & 隔离级别:小白也能懂

转账为什么必须用事务?ACID 是什么?脏读/幻读又是啥?四种隔离级别分别解决了什么、怎么解决,一篇讲透。

1

什么是事务?为什么需要它

🧾 事务 = 最小逻辑工作单元

事务(Transaction)是数据库执行的最小逻辑工作单元,是一组不可分割的 SQL 操作。

要么全部成功(提交 COMMIT),要么全部失败(回滚 ROLLBACK),不会出现部分生效。

🏦 经典例子:银行转账

A 账户扣 100,B 账户加 100。两个操作必须在一个事务里,任何一个失败都要回滚全部。

否则 A 扣了钱、B 没到账,账就平不了了。

🎬 转账为什么不能拆开执行
START TRANSACTION
UPDATE accounts SET balance = balance - 100 WHERE user='A'; -- A扣100
中途出错
UPDATE accounts SET balance = balance + 100 WHERE user='B'; -- 这步失败
ROLLBACK
如果不回滚,A 的钱就凭空没了!→ 回滚到事务开始前,A、B 都不变
COMMIT
只有两步都成功,才一起提交,A 扣 100、B 到账 100 ✅

事务通过 ACID 四个特性来保证数据的可靠性和一致性。

2

ACID 四特性

⚛️ A · 原子性 Atomicity

事务里的操作要么全部成功,要么全部不执行。

中途出错,已执行的部分也回滚到事务开始前。

InnoDB 通过 undo log 实现——回滚时用它撤销已做的修改。

🎯 C · 一致性 Consistency

事务执行前后,数据库都处在一致状态。

所有约束(主键、外键、唯一约束、CHECK)都要满足。

一致性是最终目标,A、I、D 都是保证一致性的手段。

🧊 I · 隔离性 Isolation

并发事务之间互不干扰,每个事务感觉不到其他事务在并发执行。

InnoDB 用锁机制 + MVCC实现不同隔离级别,在隔离性和性能之间权衡。

💾 D · 持久性 Durability

事务提交成功后修改就是永久的,即使系统崩溃也不丢失。

InnoDB 通过 redo log 实现——提交时把 redo log 刷盘,崩溃恢复时重放已提交的修改。

🔑
一致性是目标

A 原子性、I 隔离性、D 持久性,最终都是为了保证 C 一致性。

📝
undo log 管原子性

回滚靠 undo log 撤销已做的修改。

🔁
redo log 管持久性

崩溃恢复靠 redo log 重放已提交的修改。

🔒
锁 + MVCC 管隔离性

隔离级别越高越安全,但并发越低,要按业务权衡。

3

四个隔离级别:解决了什么、怎么解决的

隔离级别能解决遗留问题
读未提交 READ UNCOMMITTED—脏读、不可重复读、幻读
读已提交 READ COMMITTED脏读不可重复读、幻读
可重复读 REPEATABLE READ脏读、不可重复读幻读(InnoDB 已基本解决)
串行化 SERIALIZABLE脏读、不可重复读、幻读—

👀 ① 读未提交 READ UNCOMMITTED

完全不隔离,能读到别人还没提交的数据。

一个事务还没提交,另一个事务就能读到它改的值。

→ 脏读、不可重复读、幻读全都有。隔离级别最低,也最危险,几乎不用。

✅ ② 读已提交 READ COMMITTED

解决脏读:靠 MVCC 快照——每次读都生成一个新快照,只读已提交的版本,所以读不到别人未提交的脏数据。

但每次读都生成新快照,两次读之间别人提交了修改,第二次读就会变。

→ 还有不可重复读、幻读。Oracle/PostgreSQL 的默认级别。

📸 ③ 可重复读 REPEATABLE READ

解决不可重复读:靠 MVCC 快照——事务开始时生成一个快照,整个事务都读这一个,所以同一行两次读结果一样。

再加间隙锁/临键锁阻止范围插入,基本解决幻读。

→ 脏读、不可重复读都解决了。MySQL 的默认级别。

🔒 ④ 串行化 SERIALIZABLE

解决所有问题:所有读操作都加锁,事务完全串行执行,一个跑完另一个才跑。

→ 脏读、不可重复读、幻读全解决,但并发性能最低,几乎不用。

一句话串起来:隔离级别从低到高,就是「越来越严格」——读未提交什么都不管,读已提交管住脏读,可重复读再管住不可重复读,串行化全管住。

MySQL InnoDB 默认是「可重复读」,和 Oracle/PostgreSQL 默认「读已提交」不同,这是 MySQL 的一个重要区别。

4

三个并发问题:脏读 / 不可重复读 / 幻读

🧼 ① 脏读

读到别人还没提交的数据。

事务 A 改了数据还没提交,事务 B 读到了——如果 A 回滚,B 读到的就是「脏数据」。

读未提交才会发生

🔁 ② 不可重复读

同一事务里两次读同一行,结果不一样。

事务 A 先读到 balance=1000,期间事务 B 提交把 balance 改成 900,A 再读变成 900。

读已提交才会发生

👻 ③ 幻读

同一事务里两次查询,结果集行数不一样(多了/少了行)。

事务 A 查「age>20 的人」,第一次 3 行,期间 B 插入一行 25 岁的,A 再查变成 4 行——像幻觉。

可重复读理论上会有

🎬 三个问题一次看懂
脏读
A: 把 B 余额改 900(未提交)→ B 事务读到 900 → A 回滚 → B 读到的是假数据
不可重复读
A: 第一次读 balance=1000 → B 提交改成 900 → A: 第二次读变成 900(同一行变了)
幻读
A: 第一次查 age>20 有 3 行 → B 插入一行 25 岁并提交 → A: 第二次查变成 4 行(行数变了)
5

InnoDB 怎么在可重复读下避免幻读

📸 快照读(普通 SELECT)

通过 MVCC 版本链,事务内多次读取都从同一个快照取数据。

看不到其他事务新插入的行 → 避免幻读。

这就是「可重复读」的实现核心。

🔒 当前读(UPDATE / FOR UPDATE)

通过 间隙锁(Gap Lock)/ 临键锁(Next-Key Lock)锁定范围。

阻止其他事务在该范围内插入新行 → 也避免幻读。

📸

快照读

普通 SELECT
MVCC 版本链
同一快照, 看不到新插入行

VS
🔒

当前读

SELECT ... FOR UPDATE / UPDATE / DELETE
间隙锁 / 临键锁
锁范围, 阻止插入

MVCC 管快照读 + 间隙锁管当前读 = 基本避免幻读
⚡
追求更高并发

对一致性要求不高时,可改成 READ COMMITTED(SET GLOBAL transaction_isolation='READ-COMMITTED')。

🐢
SERIALIZABLE 几乎不用

性能最低,全串行,除非要求极严格一致性否则不用。

🚫
MyISAM 不支持事务

MySQL 事务只适用于 InnoDB 引擎。

⏳
大事务要避免

长时间运行的大事务会锁大量资源,尽量保持事务简短。

一句话总结

事务是数据库不可分割的一组 SQL(要么全成要么全回滚),靠 ACID 保证:原子性(undo log)、一致性(最终目标)、隔离性(锁+MVCC)、持久性(redo log)。MySQL InnoDB 默认「可重复读」,靠 MVCC 快照读 + 间隙锁基本避免了脏读/不可重复读/幻读,比 Oracle/PostgreSQL 的默认「读已提交」更高。

🎤 面试问答 · 口语化回答
事务是 MySQL 面试必考,初级岗常从这几个角度问:
面试官什么是事务?ACID 分别是什么?
你

事务是数据库执行的最小逻辑工作单元,是一组不可分割的 SQL 操作,要么全部成功提交,要么全部失败回滚。ACID 四个特性:A 原子性,要么全做要么全不做,InnoDB 靠 undo log 回滚;C 一致性,事务前后数据库都处在一致状态,所有约束满足,这是最终目标;I 隔离性,并发事务互不干扰,靠锁和 MVCC 实现;D 持久性,提交后修改就是永久的,靠 redo log 崩溃恢复。

💡 加分点:能点出「一致性是最终目标,A、I、D 是手段」以及 undo/redo log 的具体实现,面试官会觉得你有深度。
面试官MySQL 有哪几种隔离级别?默认是哪个?
你

四种,从低到高:读未提交、读已提交、可重复读、串行化。MySQL InnoDB 默认是可重复读 REPEATABLE READ,这跟 Oracle、PostgreSQL 默认读已提交不一样。读未提交会有脏读;读已提交解决了脏读但还有不可重复读和幻读;可重复读基本都解决了;串行化全解决但性能最低,几乎不用。

💡 加分点:把「MySQL 默认可重复读 vs Oracle/PG 默认读已提交」这个对比说出来,体现知识广度,是加分项。
面试官脏读、不可重复读、幻读分别是什么?
你

脏读是读到别人还没提交的数据,如果对方回滚了,我读到的就是假数据,只有读未提交会发生。不可重复读是同一事务里两次读同一行结果不一样,因为中间别的已提交事务改了这行,读已提交会发生。幻读是同一事务里两次查询结果行数不一样,多了或少了行,比如查年龄大于 20 的人第一次 3 个,别人插入一个 25 岁的我再查变 4 个,像幻觉,可重复读理论上会有。

💡 加分点:能用自己的话把三个问题讲得清晰,最好各配一个小例子,初级岗这样答就很出彩了。
📝 读完打卡 · 写下你的收获 读完了?来打卡吧
用一句话写下你从这篇学到的最大收获,检验自己是否真的懂了 👇
⏱ 00:00 🔥0分