ACID 是关系型数据库(如 MySQL、PostgreSQL、Oracle)保障数据可靠性和事务完整性的核心特性,也是区分关系型数据库与多数非关系型数据库(NoSQL)的关键标志。ACID 是四个英文单词的首字母缩写,分别代表 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),四个特性相互依赖、共同构成事务的 “安全保障体系”。
一、先明确:什么是 “事务”?
在理解 ACID 前,需先明确 “事务” 的定义:事务(Transaction)是数据库中 “一组不可分割的操作单元” —— 这组操作要么 “全部执行成功”,要么 “全部执行失败回滚”,不存在 “部分成功、部分失败” 的中间状态。例如:“银行转账”(从 A 账户扣 100 元,向 B 账户加 100 元)就是典型事务,若扣钱成功但加钱失败,会导致资金凭空消失,ACID 正是为避免这类问题而生。
二、ACID 四大特性详解(结合 “银行转账” 案例)
1. 原子性(Atomicity):“要么全成,要么全败”,不可分割
原子性是事务的 “最小执行单位” 特性,核心是事务中的所有操作 “同生共死”,不会因中间错误(如网络中断、服务器崩溃)导致 “部分执行”。
-
核心逻辑:事务执行时,数据库会记录 “操作的反向日志”(如扣钱的反向是加钱,加钱的反向是扣钱)。若事务中任意一步失败(如 B 账户不存在导致加钱失败),数据库会通过 “回滚(Rollback)” 执行反向操作,将数据恢复到事务执行前的状态;若所有步骤成功,才会 “提交(Commit)” 事务,永久生效。
-
转账案例:
- 正常情况:A 扣 100(成功)→ B 加 100(成功)→ 事务提交,数据永久生效;
- 异常情况:A 扣 100(成功)→ B 加 100(失败,如账户不存在)→ 事务回滚,A 的 100 元恢复,数据回到转账前状态,避免 “钱扣了但没到账”。
-
关键作用:防止数据因 “部分执行” 出现逻辑错误(如资金丢失、库存异常)。
-
数据库 “知道回滚多少步” 的本质
数据库不需要 “预判会失败到哪一步”,而是通过 **“执行一步就记录一步的反向操作”,形成完整的 “回滚日志链”。无论事务在第几步失败,只需从最后一步开始,倒序执行已记录的反向操作 **,就能精准回滚所有已执行的步骤,最终实现 “要么全成,要么全败” 的原子性。
这种机制的核心是:用 “日志记录每一步的退路”,替代 “预判哪一步会失败”,从而在任何失败场景下都能可靠回滚。
-
如果回滚操作本身被打断(如服务器突然断电、崩溃),数据库如何保证最终数据依然正确?这依赖于数据库的 **“崩溃恢复机制”,核心是通过“重做日志(Redo Log)” 和 “撤销日志(Undo Log)的持久化”** 实现 “即使回滚被打断,重启后仍能继续处理”。
2. 一致性(Consistency):“事务前后,数据规则不破坏”,保持合法状态
一致性是事务的 “数据合法性” 特性,核心是事务执行前后,数据库的 “业务规则” 和 “数据约束” 不被破坏(如主键唯一、字段非空、金额不为负、库存不小于 0 等)。
-
核心逻辑:一致性是 “结果导向” 的特性,依赖原子性、隔离性、持久性共同保障 —— 它要求事务本身的逻辑合法(如 “扣钱后余额不能为负”),且事务执行过程中不会因其他事务干扰导致规则破坏。
-
转账案例:
- 预设规则:账户余额不能为负,转账金额必须为正;
- 若 A 账户余额仅 50 元,却发起 “转账 100 元” 的事务:
- 事务执行时,数据库会先校验 “50 - 100 = -50” 违反 “余额非负” 规则,直接拒绝执行,事务回滚;
- 即使事务执行中出现其他问题(如并发修改),隔离性也会确保 A 的余额不会被其他事务提前扣减,从而保障 “余额非负” 的规则始终成立。
-
关键作用:确保数据始终符合业务逻辑(如 “不会出现负数库存”“不会出现重复订单号”),避免非法数据进入数据库。
3. 隔离性(Isolation):“多个事务并行时,互不干扰”,避免并发脏读
隔离性是事务的 “并发控制” 特性,核心是当多个事务同时操作同一批数据时,每个事务的执行过程 “相互隔离”,不会因交叉执行导致数据混乱(如读错未提交的数据、重复读同一数据却结果不同)。
-
核心问题:并发事务的 “干扰风险”若不考虑隔离性,多个事务并行时会出现 4 类经典问题(以 “事务 A 读数据,事务 B 改数据” 为例):
问题类型 描述(事务 A 读,事务 B 改) 转账场景举例 脏读(Dirty Read) A 读取了 B 未提交的修改(B 后续回滚,A 读的是 “无效数据”) A 查 B 余额为 200(B 刚加 100 但未提交),B 回滚后余额变回 100,A 基于 200 做决策(如转账),导致错误 不可重复读(Non-repeatable Read) A 两次读同一数据,中间被 B 提交的修改覆盖,两次结果不同 A 第一次查 B 余额 100,中间 B 转账收入 50 并提交,A 第二次查余额为 150,前后不一致 幻读(Phantom Read) A 按条件读数据(如 “余额> 100 的账户”),中间 B 新增 / 删除符合条件的数据,A 再次读时结果行数变化 A 统计 “余额> 100 的账户有 5 个”,中间 B 新增 1 个余额 200 的账户并提交,A 再次统计变成 6 个,像 “幻觉” -
数据库的隔离级别(解决并发问题)为平衡 “隔离性” 和 “并发性能”,数据库设计了 4 个隔离级别(从低到高,隔离性越强,并发性能越弱):
隔离级别 解决的问题 未解决的问题 性能 读未提交(Read Uncommitted) 无(允许读未提交数据) 脏读、不可重复读、幻读 最高 读已提交(Read Committed) 脏读 不可重复读、幻读 较高 可重复读(Repeatable Read) 脏读、不可重复读 幻读(MySQL 已优化) 中等 串行化(Serializable) 所有问题(事务串行执行) 无 最低 - 主流数据库默认隔离级别:MySQL(InnoDB)默认 “可重复读”,Oracle 默认 “读已提交”;
- 转账案例:若用 “读已提交” 隔离级别,A 只能读取 B 已提交的余额修改,避免 “读错未提交的脏数据”,同时允许其他事务并行执行,平衡安全与性能。
4. 持久性(Durability):“事务提交后,数据永久不丢”,对抗硬件故障
持久性是事务的 “数据永久性” 特性,核心是事务一旦提交(Commit),其修改的数据会 “永久保存” 到磁盘(或可靠存储),即使后续出现硬件故障(如服务器断电、磁盘损坏),数据也不会丢失。
-
核心逻辑:数据库通过 “持久化机制” 实现持久性:
- 事务提交时,数据先写入 “事务日志(如 MySQL 的 Redo Log)”—— 日志文件是顺序写入(速度快),且会立即刷到磁盘;
- 数据随后异步写入 “数据文件”(如 MySQL 的 .ibd 文件)—— 即使写入数据文件前服务器断电,重启后数据库可通过 Redo Log 恢复已提交的事务数据,确保 “提交的数据不丢失”。
-
转账案例:当 “A 扣 100、B 加 100” 的事务提交后,数据库会先将这两个操作写入 Redo Log 并刷盘;若此时服务器突然断电,重启后数据库会读取 Redo Log,重新执行 “扣 100、加 100” 的操作,确保转账结果不会因断电丢失。
-
关键作用:对抗硬件故障(断电、磁盘损坏),保障已提交的数据 “绝对安全”,是数据库可靠性的核心保障。
三、ACID 四大特性的关系:相互依赖,缺一不可
ACID 不是四个独立的特性,而是 “层层依赖、共同保障事务安全” 的体系:
- 原子性是基础:没有原子性,事务会出现 “部分执行”,一致性和持久性无从谈起;
- 一致性是目标:原子性、隔离性、持久性都是为了最终实现 “数据合法”;
- 隔离性是保障:没有隔离性,并发事务会相互干扰,破坏一致性;
- 持久性是底线:没有持久性,已提交的数据会丢失,数据库失去信任基础。
四、关键总结:ACID 的适用场景与局限
- 适用场景:必须保障数据绝对可靠的业务(如金融交易、电商支付、企业 ERP)—— 这些场景宁可牺牲部分并发性能,也要避免数据错误或丢失;
- 局限:ACID 的强约束会增加数据库的 “锁开销” 和 “日志开销”,导致并发性能较低 —— 这也是多数 NoSQL 数据库(如 Redis、MongoDB)放弃部分 ACID 特性(如强一致性、串行化隔离)以换取更高读写性能的原因。
简言之:ACID 是关系型数据库的 “安全铠甲”,确保在复杂业务和并发场景下,数据始终可靠、合法、不丢失。
五、补充:
- 事务内可见性规则:同一事务内,无论是否提交,后续操作都能看到当前事务中已执行的修改(如 INSERT/UPDATE/DELETE)。就是说在当前事务中,可以看到自己未提交的数据。
5万+

被折叠的 条评论
为什么被折叠?



