事务详解|ACID 四大特性,搞懂数据一致性的核心
前言
前面我们系统学习了多表联查、子查询、联合查询等数据查询与统计相关技能,能够完成绝大多数数据读取、报表统计业务。但在实际生产环境中,除了查数据,我们还会频繁执行增、删、改操作,尤其是一组逻辑上不可分割的连续数据变更。
举个典型场景:电商下单扣库存、转账业务(A 账户扣款、B 账户收款),这两步操作必须同时成功,或者同时失败。如果只执行一半,就会出现数据错乱、资金异常等严重问题。
想要保证一组操作整体性、可靠性,就必须使用数据库事务。事务是数据库核心机制之一,是后端开发、运维、数据分析岗位的必学内容,也是面试高频考点。本篇围绕事务定义、ACID 四大特性、手动事务操作、使用场景、拓展知识全面讲解,案例详实、规则清晰。
一、知识点汇总
- 数据库事务的定义与核心作用
- 事务的基本执行流程
- 事务四大特性:ACID(原子性、一致性、隔离性、持久性)详解
- MySQL 事务默认提交机制(自动提交)
- 手动事务语法:开启、提交、回滚
- 事务使用场景与业务案例
- 事务与锁的基础关联拓展
- 事务常见误区与职场注意事项
- 核心知识点总结
- 课后实战练习题 + 参考答案
二、知识点详解
1. 什么是事务?
事务(Transaction):将多条 SQL 语句打包成一个不可分割的逻辑执行单元。 这个单元有两种最终结果:
- 单元内所有 SQL 全部执行成功,整体生效;
- 单元内任意一条 SQL 执行失败,则所有已执行的操作全部撤销,数据恢复到执行前状态。
简单理解:同生共死,要么全成,要么全败。
核心作用
保障连续的数据变更操作不会出现 “半截执行” 的情况,维护数据库数据的完整性与正确性,避免业务数据错乱。
典型业务场景
- 金融转账:A 减钱、B 加钱
- 电商下单:生成订单、扣减商品库存、增加物流记录
- 会员充值:扣除账户余额、增加会员积分
- 批量数据修改:批量更新多条关联数据
2. MySQL 事务默认规则:自动提交
MySQL 默认开启自动提交模式(autocommit=ON):
- 每执行一条 DML 语句(INSERT/UPDATE/DELETE),数据库会立刻自动提交事务,操作永久生效;
- 单条语句不存在事务回滚的可能。
我们手动编写事务时,需要关闭自动提交,手动控制事务的开启、提交与回滚。
3. 事务基础语法(手动事务三步曲)
标准语法
sql
-- 1. 开启事务:标记事务起点 START TRANSACTION; -- 简写写法(等价) BEGIN; -- 2. 编写一组业务SQL(增/删/改) SQL语句1; SQL语句2; SQL语句3; -- 3. 二选一执行:提交 或 回滚 -- 提交事务:所有操作永久生效,事务结束 COMMIT; -- 回滚事务:撤销所有操作,数据还原,事务结束 ROLLBACK;语法补充说明
START TRANSACTION/BEGIN:显式开启事务,开启后所有 DML 操作临时生效,不会写入数据库;COMMIT:提交事务,临时数据固化到数据库,事务正常结束;ROLLBACK:回滚事务,清空所有临时操作,数据回到事务开启前状态,事务异常结束;- 事务一旦执行
COMMIT或ROLLBACK,当前事务立即终止,后续 SQL 会回归默认自动提交模式。
4. 事务四大核心特性 ACID(重点拓展)
ACID 是判断数据库事务可靠性的四大标准,所有支持事务的数据库(MySQL、Oracle、SQL Server)都必须满足。
(1)原子性(Atomicity)
核心含义:事务是最小执行单元,不可拆分。单元内的操作要么全部执行成功,要么全部回滚,不存在部分执行的情况。
- 比喻:一个炸弹,要么完整爆炸,要么完全不爆炸,不会炸一半;
- 底层实现:MySQL 通过undo log(回滚日志)记录事务执行前的数据,出错时根据日志恢复数据。
(2)一致性(Consistency)
核心含义:事务执行前后,数据库的整体数据状态、业务规则必须保持合法一致,不会被破坏。
- 规则:数据库约束(主键、外键、唯一约束)、业务逻辑规则在事务执行前后都必须成立;
- 举例:转账场景,转账前后两个账户总金额不变,这就是业务一致性;不能出现 A 扣了钱,B 没收到钱的情况。
- 补充:一致性是事务的最终目标,原子性、隔离性、持久性都是为了保障一致性。
(3)隔离性(Isolation)
核心含义:多个事务并发执行时,事务之间相互隔离、互不干扰。一个事务看不到其他未提交事务的中间数据。
- 场景拓展:多人同时操作同一张表、多个业务同时修改同一条数据;
- 延伸知识点:MySQL 提供四种事务隔离级别(下一篇详细讲解),不同隔离级别对应不同的并发问题(脏读、不可重复读、幻读);
- 通俗理解:每个人在自己的 “独立房间” 操作数据,看不到别人未确认的临时操作。
(4)持久性(Durability)
核心含义:事务一旦执行COMMIT提交成功,数据就会永久保存到数据库中,即使服务器断电、崩溃、重启,数据也不会丢失。
- 底层实现:MySQL 通过redo log(重做日志)记录已提交的事务,数据库重启后会根据日志恢复数据;
- 关键点:提交成功 = 数据永久生效,回滚 / 未提交 = 数据不生效。
ACID 整体关系总结
原子性保证执行单元完整,隔离性保证并发互不干扰,持久性保证提交后数据不丢失,三者共同服务于一致性,最终保障数据合法有效。
5. 拓展:事务的生效范围与限制
- 仅针对 DML 语句:事务只作用于
INSERT / UPDATE / DELETE(数据操作语言);DDL 语句(CREATE/ALTER/DROP 建表、改表、删表)无法回滚,执行即永久生效。 - 会话级别隔离:手动事务仅在当前数据库连接会话内生效,新的客户端会话看不到未提交的临时数据。
- 事务嵌套:MySQL不支持事务嵌套,开启多个
BEGIN只会视为同一个事务。
三、实战环境准备(可直接复制运行)
我们创建账户表,模拟最经典的转账业务,用于演示事务的提交与回滚。
sql
-- 创建账户表 CREATE TABLE account ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(20) NOT NULL COMMENT '账户名', balance DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '账户余额' ) COMMENT = '用户账户表'; -- 插入测试数据:两个账户,初始余额各1000元 INSERT INTO account(username, balance) VALUES ('张三', 1000.00), ('李四', 1000.00);查询初始数据:
sql
SELECT * FROM account;初始结果:张三 1000,李四 1000,总金额 2000 元。
四、应用案例及结果分析
案例 1:正常事务(全部执行成功 + 提交 COMMIT)
业务需求:张三向李四转账 200 元,两条更新语句放在同一个事务中。
sql
-- 1. 开启事务 BEGIN; -- 2. 业务SQL:张三扣款200 UPDATE account SET balance = balance - 200 WHERE username = '张三'; -- 3. 业务SQL:李四收款200 UPDATE account SET balance = balance + 200 WHERE username = '李四'; -- 4. 提交事务,数据永久生效 COMMIT;结果分析
- 两条 UPDATE 语句全部正常执行,执行
COMMIT后事务结束; - 查询数据:张三余额
800.00,李四余额1200.00; - 总金额依旧为 2000 元,数据一致性完好;
- 关闭客户端重新连接,数据保持不变(持久性生效)。
案例 2:异常事务(中间出错 + 回滚 ROLLBACK)
业务需求:模拟转账过程中出现异常(人为制造 SQL 错误),验证事务回滚效果。
sql
-- 1. 开启事务 BEGIN; -- 2. 张三扣款200(正常执行) UPDATE account SET balance = balance - 200 WHERE username = '张三'; -- 3. 故意编写错误SQL(字段名错误,触发执行异常) UPDATE account SET bal = balance + 200 WHERE username = '李四'; -- 4. 执行回滚,撤销所有操作 ROLLBACK;结果分析
- 第一条扣款语句临时生效,但第二条 SQL 报错;
- 执行
ROLLBACK后,所有操作全部撤销; - 最终数据恢复为:张三 1000,李四 1000,没有出现扣款不收款的异常;
- 完美体现事务原子性:要么全成,要么全败。
案例 3:未提交事务(临时数据,其他会话不可见)
业务演示:验证事务隔离性
- 打开第一个客户端会话,执行:
sql
BEGIN; UPDATE account SET balance = balance - 100 WHERE username = '张三'; -- 不执行COMMIT/ROLLBACK,事务处于未提交状态当前会话查询:张三余额变为 900。
- 打开第二个全新客户端会话,查询账户表:
sql
SELECT * FROM account;结果分析
第二个会话查询到的数据依旧是原始数据,看不到第一个会话未提交的临时修改。这就是事务隔离性的直观体现。
五、注意事项(避坑指南)
- DDL 语句无法回滚在建表、删表、修改表结构的 DDL 语句前后,事务会被自动提交,不要将 DDL 放入事务中。
- 大事务严禁滥用事务执行期间会占用数据库锁,长时间未提交的大事务会导致其他会话卡顿、锁等待,生产环境尽量缩小事务范围,只包裹核心 DML 语句。
- 忘记 COMMIT/ROLLBACK 是严重失误手动开启事务后,若长期不提交 / 回滚,事务会一直挂起,占用资源、阻塞其他操作。
- 自动提交模式区分测试环境可以临时关闭自动提交(
SET autocommit = 0;),生产环境建议显式手动开启事务,逻辑更清晰。 - 事务内避免复杂查询事务中尽量只写增删改语句,不要嵌套大量复杂子查询、多表联查,延长事务执行时间。
- 回滚只针对当前事务
ROLLBACK只能撤销当前未提交事务的操作,已COMMIT的数据无法回滚。
拓展:关闭 / 开启自动提交的语法
sql
-- 关闭自动提交(当前会话生效) SET autocommit = 0; -- 开启自动提交(恢复默认) SET autocommit = 1;六、核心总结
- 事务定义:将多条 DML 语句打包为一个执行单元,遵循 “全成功或全失败”。
- 基础语法:
BEGIN/START TRANSACTION开启 → 执行业务 SQL →COMMIT提交 /ROLLBACK回滚。 - ACID 四大特性
- 原子性:不可拆分,整体执行;
- 一致性:事务前后数据、业务规则合法;
- 隔离性:并发事务相互隔离,互不干扰;
- 持久性:提交后数据永久保存。
- 适用场景:转账、下单、库存变更等一组关联的数据修改操作。
- 职场红线:DDL 不支持回滚、杜绝超大事务、事务结束必须提交或回滚。
一句话记忆:事务打包 SQL 组,原子执行不分家;ACID 四性保数据,提交永久回滚擦;大事务要少使用,DDL 语句别乱加。
七、练习题(附答案思路)
题目 1
基于 account 账户表,编写事务 SQL:王五向赵六转账 300 元,保证操作整体性。
题目 2
模拟异常场景:开启事务,先给张三增加 500 元余额,再编写一条错误 SQL,最后执行回滚,验证数据是否还原。
题目 3
简述事务 ACID 四大特性的含义(面试简答题)。
参考答案思路
题目 1
sql
BEGIN; UPDATE account SET balance = balance - 300 WHERE username = '王五'; UPDATE account SET balance = balance + 300 WHERE username = '赵六'; COMMIT;题目 2
sql
BEGIN; UPDATE account SET balance = balance + 500 WHERE username = '张三'; -- 错误SQL(故意写错字段) UPDATE account SET abc = 100 WHERE id = 1; -- 回滚 ROLLBACK; -- 最终张三余额保持不变题目 3 参考答案
- 原子性:事务是最小执行单元,操作不可分割,全部成功或全部撤销;
- 一致性:事务执行前后,数据库数据和业务规则保持一致;
- 隔离性:多个并发事务互相隔离,未提交的数据对其他事务不可见;
- 持久性:事务提交成功后,数据永久保存,不受服务器故障影响。
