什么是数据库事务?一文搞懂 ACID 四大特性(一)

发布时间:2026/7/11 5:08:31
什么是数据库事务?一文搞懂 ACID 四大特性(一) 数据库事务系列 · 第 1 篇引言一次转账引发的数据危机想象你正在开发银行转账系统的核心模块。用户张三发起一笔1000元的转账给李四程序逻辑清晰地分为两步张三账户余额减少1000元。李四账户余额增加1000元。一切看似完美。然而就在程序成功执行完第一步、正准备执行第二步时数据库服务器突然宕机了。系统重启后你惊恐地发现张三的账户确实少了1000元但李四的账户余额却纹丝不动。那这1000元凭空消失了。更可怕的是没有任何错误日志能告诉你发生了什么。这就是没有事务机制的数据库世界——每个操作都是孤立的个体一次意外就可能导致数据永久性地陷入不一致状态。为了解决这类问题数据库引入了**事务Transaction**这一核心概念。一、事务的概念一组操作的“生死契约”事务是一组数据库操作的集合它是数据库执行的最小逻辑单元。这个单元有一个不可动摇的铁律这组操作要么全部成功提交COMMIT要么全部失败回滚ROLLBACK。绝不允许“成功一半”的中间状态存在。案例聚焦回到转账案例在事务的保护下它变成了一个不可分割的整体。-- 这是一个完整的事务-- 操作1张三账户减1000UPDATEaccountSETbalancebalance-1000WHEREname张三;-- 操作2李四账户加1000UPDATEaccountSETbalancebalance1000WHEREname李四;-- 如果上述两步都成功则执行 COMMIT提交数据永久生效。-- 如果任何一步失败则执行 ROLLBACK回滚两步操作全部撤销。正常世界两条UPDATE都成功数据库执行COMMIT。数据更新皆大欢喜。异常世界步骤1成功步骤2失败如网络超时、账户异常。事务机制会立即执行ROLLBACK将张三的余额恢复到修改前的状态。最终结果是张三钱没少李四钱没多数据依然保持一致。事务的本质它为应用程序提供了一种简化的编程模型。程序员只需告诉数据库“要么全做要么全不做”而无需在代码中处理复杂的并发、网络、硬件等底层异常。事务是应用层与复杂数据层之间的可靠“契约”。二、事务的四大特性ACID四大护法缺一不可正是ACID这四个特性共同构成了事务的完整承诺。我们用转账案例逐一剖析每个特性的角色。1. 原子性Atomicity——“全做或全不做”案例聚焦原子性保证了张三扣钱和李四加钱必须作为一个整体执行。如果李四加钱失败整个事务会回滚张三的扣钱操作也会被撤销。你永远不会看到“钱扣了但没到账”这种中间状态。技术基石原子性由Undo Log回滚日志保障。每次修改数据前数据库都会在Undo Log中记录修改前的旧值。一旦需要回滚数据库就利用这些旧值将数据恢复原状仿佛操作从未发生。2. 一致性Consistency——“合法才是王道”案例聚焦一致性要求事务执行前后张三和李四的账户总金额必须保持不变10002000 11001900。同时如果表上有“余额不能为负”的约束一致性也保证不会出现负余额。关键说明一致性需要应用层和数据库共同保证。数据库能确保其自身约束如主键、外键不被破坏。但像“转账总额不变”这样的业务规则一致性必须由你的代码正确地执行两条UPDATE来保证。如果代码只扣了张三的钱而忘了给李四加钱数据库的约束依然满足但业务上已经不一致了。3. 隔离性Isolation——“让并发事务和平共处”案例聚焦当张三给李四转账的同时王五也在给李四转账。隔离性确保了这两个并发的事务不会互相干扰。一个事务不会读取到另一个事务尚未提交的中间状态比如“李四账户加了1000”但事务还未提交。技术基石隔离性主要通过锁机制和MVCC多版本并发控制实现。数据库提供了四种隔离级别在数据一致性和并发性能之间做权衡。我们将在本系列第2、3篇中深入剖析届时你会看到“脏读”、“不可重复读”等现象是如何产生和解决的。4. 持久性Durability——“一旦提交永不遗忘”案例聚焦当客户端收到“转账成功”的提示后哪怕数据库所在机房突然断电重启后张三扣1000、李四加1000的最终结果依然必须存在。数据不能因为系统故障而回退。技术基石持久性由Redo Log重做日志保障。数据修改时会先以顺序写的方式快速写入Redo Log并立即返回“提交成功”。之后数据库后台才会慢慢将数据刷新到磁盘。即使刷盘前系统崩溃重启后也能根据Redo Log重做已提交的事务确保数据不丢失。核心总结Undo Log 保证了“可以撤回来”Redo Log 保证了“提交了不丢”。原子性、隔离性、持久性A、I、D三者最终共同服务于一致性C这个终极目标确保数据库从一个正确状态转移到另一个正确状态。三、事务的版本支持选对引擎是前提理解了ACID的理论我们进入实操前的最后一步准备确认MySQL环境的支持情况。在MySQL中并不是所有存储引擎都支持事务。这直接决定了你能否使用BEGIN、COMMIT、ROLLBACK等命令。InnoDB默认引擎完整支持事务。所有ACID特性及相关的并发控制机制都在InnoDB中实现。使用事务必须确保表使用InnoDB引擎。MyISAM早期引擎不支持事务。在其上执行事务命令不会报错但不会有任何回滚或提交的效果。你可以通过以下命令查看MySQL支持的引擎及事务支持情况SHOWENGINES;重点关注Engine引擎名和Transactions是否支持事务两列。只有标记为YES的引擎才能使用事务。因此创建表时务必指定或确认默认引擎为InnoDBCREATETABLEaccount(idINTPRIMARYKEY,nameVARCHAR(20),balanceDECIMAL(10,2))ENGINEInnoDB;-- 明确指定引擎四、事务的提交方式与实操演示现在我们具备了所有理论基础和环境前提开始动手验证。1. 提交方式MySQL默认采用自动提交AUTOCOMMIT1。这意味着每条DML语句执行后都会自动被提交为一个独立的事务。查看当前提交方式SHOWVARIABLESLIKEautocommit;设置提交方式在演示中我们通常通过显式BEGIN来开启事务它会临时影响提交行为-- 关闭自动提交改为手动SETautocommit0;-- 或直接使用 BEGIN/START TRANSACTION 显式开启事务2. 核心事务命令速查命令作用BEGIN;/START TRANSACTION;开启一个事务。SAVEPOINT 名称;在事务内创建保存点存档。ROLLBACK TO 名称;回滚到指定保存点。ROLLBACK;回滚整个事务到开始状态。COMMIT;提交事务使所有更改永久生效。3. 完整实操演示见证原子性与持久性为了直观展示我们使用两个MySQL会话终端A和终端B。请先将两个终端的隔离级别临时设置为READ UNCOMMITTED以便我们在事务未提交时也能看到数据变化从而完整追踪过程。SETSESSIONTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;第一阶段开启事务与分段操作终端A开启事务BEGIN;终端A插入数据INSERT INTO account VALUES (1, 张三, 100);终端B查询SELECT * FROM account;→ 可以看到“张三”记录。终端A创建保存点SAVEPOINT s1;终端A插入数据INSERT INTO account VALUES (2, 李四, 10000);终端B查询SELECT * FROM account;→ 可以看到两条记录。第二阶段部分回滚展现原子性的控制力终端A回滚到保存点ROLLBACK TO s1;终端B查询SELECT * FROM account;→结果只显示“张三”“李四”记录消失。结论事务可以精确回滚到任意保存点证明了原子性的“全做或全不做”的控制能力。第三阶段完整回滚 vs 最终提交对比原子性的终结与持久性的开始终端A回滚整个事务ROLLBACK;终端B查询SELECT * FROM account;→ 表只剩张三。现在重新开启事务对比提交的效果终端A重新开启事务BEGIN;终端A插入数据INSERT INTO account VALUES (1, 张三, 100);终端A直接提交COMMIT;终端B查询SELECT * FROM account;→ “张三”记录永久存在。第四阶段模拟崩溃验证持久性模拟崩溃强制关闭终端A的连接。终端B再次查询SELECT * FROM account;最终结果“张三”记录完好无损。结论一旦COMMIT修改就永久生效即使客户端崩溃也无法影响证明了持久性。五、总结本文作为MySQL事务系列的第一篇我们完成了以下学习事务的概念一组不可分割的操作集合要么全成功COMMIT要么全失败ROLLBACK。ACID四大特性原子性A由Undo Log保障。一致性C最终目标需应用层逻辑保证。隔离性I由锁和MVCC保障。持久性D由Redo Log保障。使用前提表引擎必须是InnoDB。核心操作通过实操演示了BEGIN、COMMIT、ROLLBACK、SAVEPOINT命令并验证了原子性和持久性。 下篇预告事务的隔离性是ACID中最精妙也最复杂的部分。多个事务并发执行时会产生哪些问题脏读、不可重复读、幻读具体指什么四种隔离级别又是如何应对它们的下一篇我们将用大量实操演示深入剖析这些并发问题的本质。敬请期待*通过实操演示了BEGIN、COMMIT、ROLLBACK、SAVEPOINT命令并验证了原子性和持久性。