事务基础
ACID、BEGIN/COMMIT/ROLLBACK。
事务基础
这一课你将能做到
- 用 START TRANSACTION / COMMIT / ROLLBACK 手动管理事务,并用转账例子演示「要么全成、要么全不做」
- 用自己的话解释 ACID 四性和 MySQL 的四个隔离级别(默认 REPEATABLE READ)
- 把 SQL 事务映射到 Spring Boot 的
@Transactional,说出至少三个注解失效场景
前置:第一课建库脚本已跑(前面课改过余额的话先重跑复原,保证对得上输出)。
为什么要学
真实业务的一条逻辑往往要连续改好几张表:买课 = 扣余额 + 插订单 + 生成学习记录。三步做到一半服务崩了怎么办?余额扣了订单没生成,钱就凭空消失。事务就是数据库给的答案:把多条 SQL 捆成一个「全做或全不做」的单元。这也是 InnoDB 压倒 MyISAM 的核心优势,Java 后端面试的必考题(ACID、隔离级别、@Transactional 失效场景三连问)。
先建立图像
转账 = 两步 UPDATE,必须同生共死
START TRANSACTION;
老陈 balance 128 → 78 (步骤①)
小林 balance 39 → 89 (步骤②)
┌─ 一切正常 ──────────────→ COMMIT:两步对外同时生效
└─ 中间任何环节出错 ──────→ ROLLBACK:两步一起当没发生过
COMMIT 之前,改动只有当前连接自己看得见;COMMIT 之后才对所有人生效、落盘持久。
跟着做
步骤 1:认识 autocommit
SELECT @@autocommit; -- 1
MySQL 默认开启自动提交:每条语句自带一个隐式事务,执行完立即生效。前面课里的 INSERT/UPDATE 所以「一敲就生效」。显式事务就是把多条语句从「各自为政」改成「打包结算」。
步骤 2:ROLLBACK——全没发生过
START TRANSACTION;
UPDATE student SET balance = balance - 50 WHERE id = 1; -- 老陈 128 → 78
UPDATE student SET balance = balance + 50 WHERE id = 2; -- 小林 39 → 89
SELECT id, name, balance FROM student WHERE id IN (1, 2);
-- 当前事务里看到:78 / 89
ROLLBACK;
SELECT id, name, balance FROM student WHERE id IN (1, 2);
-- 回到 128 / 39,两步 UPDATE 一起作废
步骤 3:COMMIT——一起生效
START TRANSACTION;
UPDATE student SET balance = balance - 50 WHERE id = 1;
UPDATE student SET balance = balance + 50 WHERE id = 2;
COMMIT; -- 结算,改动对外生效并持久化
SELECT id, name, balance FROM student WHERE id IN (1, 2); -- 78 / 89
把老陈和小林改回初始值,方便后面课对照:
START TRANSACTION;
UPDATE student SET balance = balance + 50 WHERE id = 1;
UPDATE student SET balance = balance - 50 WHERE id = 2;
COMMIT;
步骤 4:应用层异常 → 自动回滚
先在 SQL 里看「扣钱前检查余额」的防御式写法(这条语句本身就该这么写):
-- 余额不够就什么都不发生:affected rows = 0,应用层据此中断流程
UPDATE student SET balance = balance - 500
WHERE id = 1 AND balance >= 500;
-- 老陈只有 128,影响 0 行
再到 Java 侧,@Transactional 会在抛异常时替你执行 ROLLBACK(完整示例见步骤 6)。