InnoDB 的事务四大特性(ACID),以及 InnoDB 是如何通过机制来保证事务四大特性的?

✅ 一、事务的四大特性(ACID)

特性中文名简单解释举例说明
A - Atomicity原子性一个事务里的所有操作是一个整体,要么全部执行成功,要么一个不成功就全部失败,不能只执行一半。假如你从账户A转100元到账户B,需要先从A扣掉100,再给B加上100。如果在加给B的时候系统突然崩溃了,原子性保证整个操作会被回滚,不会只扣了A的钱但B没收到。
C - Consistency一致性执行事务前后,数据库的数据必须是符合规则的、没有错误的假如银行要求所有账户总金额为2000元,无论有多少人转账,执行完所有操作后,总金额仍然必须是2000元,不能多也不能少。这叫做一致性。
I - Isolation隔离性多个事务同时执行时,互不影响,彼此之间看不到对方未提交的操作张三在转账,还没提交,李四正在查账户余额。隔离性保证李四看到的还是“转账前的余额”,而不是张三操作中的“中间状态”。避免脏读、不可重复读、幻读
D - Durability持久性一旦事务提交成功,对数据库的修改就是永久保存的,即使系统崩溃、断电也不会丢失。比如你网购后点击“支付”,系统提示支付成功,这时即使服务器突然断电,再次启动时订单依然是“已支付”,不会消失,这就是持久性。

📌 补充说明:几个常见名词解释(防止小白看不懂)

术语含义示例
事务(Transaction)一组操作,要么一起成功,要么一起失败的执行单元转账中的“扣钱”和“加钱”就组成一个事务
脏读(Dirty Read)读到了其他事务未提交的数据A刚修改了账户余额,B立刻读取,结果A回滚了,但B读到的是“脏”的
不可重复读(Non-repeatable Read)同一个事务中两次读取结果不同第一次查余额是100元,第二次又变成了80元,因为别的事务中间改了
幻读(Phantom Read)同一事务中读取到新插入的“额外数据”第一次查订单数是5,后面查变成了6,因为别的事务插入了新订单

📌注:“不可重复读”好一点,读到的是 已提交 的数据,比如某个读事务持续时间比较长,期间多次读取某个元组,每次读到的都是被别人改过并已提交的不同数据。 可以理解为在执行任务的过程中,领导的指令一直在变。 但好歹是正式下达的指令。 “幻读”是指读的过程中,某些元组被增加或删除,这样进行一些集合操作,比如算总数,平均值等等,就会每次算出不一样的数。 所以“不可重复读”和“幻读”都是读的过程中数据前后不一致,只是前者侧重于修改,后者侧重于增删。 个人认为,严格来讲“幻读”可以被称为“不可重复读”的一种特殊情况,没错的。 但是从数据库管理的角度来看二者是有区别的。

✅ 二、InnoDB 如何保证原子性(Atomicity)

🔍 什么是原子性?

“原子性”表示一个事务中的操作要么全部成功、要么全部失败,中间不能只完成一半。

比如银行转账,“扣钱”和“加钱”必须一起成功或一起失败,不能出现扣了钱但没加上。

✔ 关键机制:Undo Log(回滚日志)

InnoDB 使用一种叫做 Undo Log(撤销日志) 的机制来保证原子性。

📌 Undo Log 是什么?

Undo Log 是数据库记录的**“修改前的数据”,可以让数据库在需要时把数据恢复成修改前的状态**。

⚙ Undo Log 的工作流程:

步骤说明
1️⃣每当你执行一个会修改数据的操作(如 INSERT、UPDATE、DELETE)时,InnoDB 会先把原始的数据保存到 Undo Log 中
2️⃣如果事务中间出现问题,比如程序崩溃、断电,或者你手动回滚(ROLLBACK),InnoDB 会根据 Undo Log,把数据恢复回原来的样子
3️⃣只有当你执行 COMMIT 提交事务后,Undo Log 才会被“清理”掉

💡 举个具体的例子:

🏦 假设你在使用银行转账应用,执行了以下操作:

BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1; -- A账户扣100元
UPDATE account SET balance = balance + 100 WHERE id = 2; -- B账户加100元
COMMIT;

💥 假如在第二步(B账户加钱)时,系统突然崩溃了:
  • InnoDB 已经在第1步时,把账户A“原来的余额”写进了 Undo Log;

  • 程序崩溃后,数据库自动回滚事务;

  • InnoDB 会从 Undo Log 中读取 A 账户原来的余额,再把数据恢复回去;

  • 最终 A 和 B 账户都不会有任何变化,转账操作就像从没发生过一样。

这就叫做:要么全部成功(扣钱 + 加钱 + 提交),要么全部失败(回滚到原样),符合“原子性”。

🧠 相关名词解释(针对小白)

名词意思举例说明
Undo Log(回滚日志)存储被修改前的数据,用于“撤销”A账户原来有1000元,UPDATE 执行前将 1000 记录到 Undo Log
事务(Transaction)一组操作,要么全部成功,要么全部失败扣钱 + 加钱 = 一个完整的转账操作
ROLLBACK手动撤销事务比如你中途发现转账金额写错了,可以输入 ROLLBACK; 来撤销
COMMIT提交事务,表示“确认生效”没有 COMMIT,修改不会真正保存下来

📝 总结一句话:

InnoDB 用 Undo Log 记录每一次修改前的数据,在事务失败时可以“反悔”,把所有操作都撤销,从而保证了事务的原子性

✅ 三、InnoDB 如何保证一致性(Consistency)

🔍 什么是“一致性”?

一致性指的是:事务执行前后,数据库中的数据都必须处于一种“合法的、符合规则的状态”。

通俗讲:

就算系统中断、电源断了、事务失败了,数据库不能出现“逻辑错误”或“数据混乱”的情况,比如不能有两个相同主键,不能引用不存在的外键等等。


✔ 一致性的实现依赖三方面机制:

机制作用通俗理解
原子性保证操作要么都成功、要么全失败比如转账时钱不能只扣不加
隔离性并发事务之间互不干扰,防止读取或修改到“中间状态”的数据别人在修改时,你读到的数据必须是“稳定”的
数据库约束机制使用主键、外键、唯一约束、触发器等,强制要求数据必须合法插入数据时必须符合规则,否则就不让你插入

📌 举例说明(一致性在生活中的体现):

💡 场景1:主键唯一性约束

你有一张用户表 user,主键是 id

INSERT INTO user (id, name) VALUES (1, 'Alice');
INSERT INTO user (id, name) VALUES (1, 'Bob'); -- ❌ 报错,id=1 已存在

🧠 为什么报错?
因为主键必须唯一,不能有两个 id=1 的用户,插入第二条数据会破坏一致性,所以被数据库拒绝了。

💡 场景2:外键约束

你有两张表:订单表 orders 和用户表 userorders.user_id 是外键,必须指向 user.id

-- 用户表
INSERT INTO user (id, name) VALUES (10, 'Tom');

-- 插入订单,引用已存在的用户
INSERT INTO orders (id, user_id, item) VALUES (1, 10, 'Book'); ✅ 成功

-- 插入订单,引用不存在的用户
INSERT INTO orders (id, user_id, item) VALUES (2, 999, 'Pen'); ❌ 报错

🧠 为什么会失败?
user_id=999 在用户表中不存在,这会破坏数据的“引用关系”,导致数据库不一致,所以插入失败。

💡 场景3:删除有关联的外键数据

-- 如果订单表中有 user_id = 10 的记录:
DELETE FROM user WHERE id = 10; -- ❌ 报错
🧠 原因: 你不能直接删除 id=10 的用户,因为还有订单在用这个用户的信息。要么先删除订单,要么使用 ON DELETE CASCADE 设置级联删除。

🧠 小白术语解释

名词解释举例
一致性数据必须始终符合设定的规则,不能出现逻辑错误不允许重复主键、不允许引用不存在的数据
主键(Primary Key)表中用来唯一标识一行的字段用户表中的 id 就是主键,不能重复
外键(Foreign Key)表中的某个字段,必须指向另一个表的主键订单表的 user_id 必须对应用户表的 id
唯一约束(Unique)要求某个字段的值不能重复邮箱字段不能重复,每个用户一个邮箱
触发器(Trigger)数据库自动执行的一段规则比如插入订单时自动写日志

🗣 一句话总结:一致性就是“永远不能让数据库出现脏乱差的状态”。InnoDB 靠原子性、隔离性和规则强校验,确保数据始终干净整洁、逻辑自洽。

✅ 四、InnoDB 如何保证 隔离性(Isolation)

🔍 什么是“隔离性”?

隔离性指的是:

多个事务同时进行时,它们之间互不干扰,每个事务在执行过程中,都感觉自己是“独占”数据库的。

换句话说:

你做事的时候不被别人打扰,你也不会看到别人未完成的“半成品”。


✅ InnoDB 的两大隔离性保障机制:


✔ 机制一:MVCC(多版本并发控制)

📌 核心思想:

不让事务之间抢锁、打架,而是给每个事务看一份“数据快照”版本,只读自己的版本数据,互不干扰。

🔧 MVCC 的构成:
组件含义通俗解释
Undo Log(回滚日志)存储旧版本数据,便于回滚或快照读取就像给数据拍了“旧照片”,用于还原
版本号字段每条记录有两个隐藏字段:创建版本号删除版本号谁创建、谁删除都有“时间戳”标记,方便判断可见性
事务版本号每个事务开始时会获得一个版本号类似于“进房间”的时间,控制它能看什么
🧠 怎么工作?

假设当前有一条数据:

订单ID: 1,金额: 200,创建版本号: 10,删除版本号: 0(表示未删除)

  • 如果你是一个 版本号为15的事务,你可以看到这条数据;

  • 如果你是一个 版本号为9的事务,你看不到,因为它是你之后才创建的

📎 哪些隔离级别用到 MVCC?

隔离级别是否使用 MVCC?是否加锁?
READ COMMITTED(读已提交)✅ 是❌ 否,快照随时更新
REPEATABLE READ(可重复读)✅ 是❌ 否,事务期间快照固定

📌 举个例子:

-- 事务A
BEGIN;
SELECT * FROM orders WHERE amount > 100;

-- 事务B
UPDATE orders SET amount = 80 WHERE id = 1;
COMMIT;

  • 事务A查询时,看到的是执行时刻的数据快照;

  • 事务B即使修改了数据,但事务A仍然看到“原来的版本”,直到它提交。

✔ 机制二:锁机制

🔐 类型 1:共享锁(S锁)
  • 用于读操作

  • 允许多个事务同时读

  • 但不允许别人写(写时需等读完)

🔐 类型 2:排他锁(X锁)
  • 用于写操作

  • 拿到排他锁的人,谁也别想读写

  • 确保写数据时不会被别人看到或修改

🔐 类型 3:Next-Key Lock(行锁 + 间隙锁)
  • 是为了防止“幻读”(新插入的行突然出现)

  • 锁住的不仅是已有数据行,还包括数据之间的空隙

  • 默认启用在 REPEATABLE READ 隔离级别下

📌 举例说明:防止幻读

💡 场景:

两个事务并发执行:

-- 事务A
BEGIN;
SELECT * FROM orders WHERE amount > 100;

-- 事务B
INSERT INTO orders (id, amount) VALUES (101, 200);
COMMIT;

🔍 如果没有 Next-Key Lock:
  • 事务A查到了 0 行;

  • 事务B插入了一行 amount = 200;

  • 事务A再次查,突然看到这行,就出现了“幻觉”!

🔐 有了 Next-Key Lock:
  • 事务A在执行 SELECT 时,会锁住符合条件范围的记录和空隙;

  • 事务B想插入一行 amount = 200 的订单,就被挡住了,必须等事务A提交。

🧠 这样就实现了隔离性,避免事务B“闯进”事务A的查询区域

🧠 小白术语解释

名词含义举例
MVCC多版本并发控制,为每个事务提供数据快照,避免加锁类似于每人一个账本副本
Undo Log回滚日志,用于还原或读取旧数据版本数据改动前先存一份原件
版本号标记记录创建和删除的事务号谁修改、删除数据都有“时间戳”
共享锁(S锁)多人可以读,不能写多人查图书馆书,但不能改书
排他锁(X锁)一人能读写,别人不能碰改作业时老师独占操作权限
Next-Key Lock锁定行和行之间的空隙,防止幻读像电影院锁住你左右空座,防止别人突然后入

📋 小结

保障机制描述是否加锁?
✅ MVCC(多版本并发控制)事务之间各看各的数据快照❌ 不加锁,提升读性能
✅ 锁机制(S/X/Next-Key)保证事务之间互不干扰,防止幻读等问题✅ 根据操作加锁

🗣 总结一句话:MVCC 负责让事务读到稳定版本的数据,锁机制负责在写时隔离事务冲突。两者联手,InnoDB 实现了强大的事务隔离能力。

✅ 五、InnoDB 如何保证 持久性(Durability)

🔍 什么是“持久性”?

持久性指的是:

一旦事务提交,修改的数据就必须被永久保存,即使断电、宕机也不会丢失。

简单来说:

“你说保存了,那就必须真的保存下来,谁也不能改口!”


✔ 关键机制:Redo Log(重做日志)

InnoDB 使用 Redo Log(重做日志)来保证数据最终会写入磁盘,确保数据不会因为系统崩溃而丢失。

📦 Redo Log 是什么?
  • 是一份物理日志,记录了哪些数据页发生了什么变化;

  • 写入日志的速度比直接写入磁盘要快得多(因为磁盘慢);

  • 一旦崩溃,就靠它来“重做”数据操作,让数据恢复到提交状态


⚙️ 事务提交流程:

🧩 核心原则:WAL 策略(Write-Ahead Logging)

WAL 原则:

先写日志(Redo Log),再写磁盘(数据页)。

⏱ 步骤流程:
  1. 执行 SQL,如 UPDATE

  2. 把更改内容写入 Redo Log(写日志)。

  3. Redo Log 写入成功后,事务才允许 COMMIT 提交

  4. 后台慢慢把数据写入真实磁盘文件。

📌 举例说明:

BEGIN;
UPDATE users SET age = 25 WHERE id = 123;
COMMIT;

假设:
  • 用户123的年龄从 24 改为 25;

  • COMMIT 后突然 断电 或系统崩溃。

会发生什么?
  • Redo Log 中已经记录了:用户123的 age 改为 25 的修改细节

  • InnoDB 重启后自动扫描 Redo Log;

  • 系统自动重做之前的更新,保证 age = 25 不会丢失!

🧠 小白术语解释:

名词含义小白理解
Redo Log记录对数据的“物理更改”,用于崩溃恢复提前写的“备份剧本”
WAL 策略Write-Ahead Logging:先写日志,再写磁盘类似写日记:先记下来,再处理
事务提交(COMMIT)表示事务完成,数据需要永久保存就像点“保存按钮”
磁盘刷盘(Flush)把数据从内存写入真实硬盘真正落地,数据就稳了

✅ 六、总结表格(详细版)

✅ 事务特性InnoDB 实现机制解释(通俗易懂)
原子性(Atomicity)✅ Undo Log(回滚日志)每个操作都记录旧值,一旦失败就能“撤回”,事务要么全成功、要么全失败
一致性(Consistency)✅ 原子性 + 隔离性 + 数据库约束(主键、外键、唯一索引等)确保数据始终合法,比如:不能插入重复主键、不能删除被引用的外键
隔离性(Isolation)✅ MVCC(快照读)、Next-Key Lock(防幻读)、行锁(S锁/X锁)每个事务有自己看的“快照”,还用锁机制防止别人插入或修改数据干扰自己
持久性(Durability)✅ Redo Log(重做日志)+ WAL 策略提交事务前先写日志,哪怕系统崩溃,日志也能把数据恢复回来,不会丢失
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值