SQL 事务处理
理解 ACID 和 BEGIN/COMMIT/ROLLBACK · 难度:高级 · +15XP
SQL 事务处理(TRANSACTION)
事务(Transaction)是数据库中最核心的概念之一,它确保一组 SQL 操作要么全部成功,要么全部失败,就像一个原子操作一样不可分割。经典的例子是银行转账:从账户 A 扣款和向账户 B 加款必须同时成功或同时失败,绝不允许出现 A 扣了钱但 B 没收到的中间状态。事务通过 BEGIN、COMMIT 和 ROLLBACK 三个命令来实现这种原子性保障。
事务的基本命令
| 命令 | 作用 |
|---|---|
BEGIN 或 START TRANSACTION | 开始一个事务 |
COMMIT | 提交事务,永久保存所有修改 |
ROLLBACK | 回滚事务,撤销所有未提交的修改 |
SAVEPOINT 名称 | 设置保存点,可部分回滚 |
ROLLBACK TO 名称 | 回滚到指定保存点 |
事务完整示例
银行转账——最经典的事务应用场景:
-- 开始事务
BEGIN;
-- 步骤1:从账户A扣除100元
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 步骤2:向账户B增加100元
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 步骤3:记录转账日志
INSERT INTO transfer_log(from_id, to_id, amount, time)
VALUES (1, 2, 100, DATETIME('now'));
-- 所有操作都成功,提交事务
COMMIT;
如果中间任何一步失败,执行 ROLLBACK 即可撤销所有修改:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 假设这里发现账户B不存在!
ROLLBACK; -- 撤销扣款,账户A余额恢复
ACID 四大特性
事务必须满足 ACID 特性才能保证数据的可靠性:
- 原子性(Atomicity):事务中的所有操作是一个整体,要么全部完成,要么全部不做
- 一致性(Consistency):事务执行前后,数据库必须从一个一致状态转变到另一个一致状态(如转账前后总金额不变)
- 隔离性(Isolation):多个事务并发执行时互不干扰,各自看到的数据视图是独立的
- 持久性(Durability):一旦事务提交成功,其修改就会永久保存在数据库中,即使系统崩溃也不丢失
事务的隔离级别
SQL 标准定义了四种隔离级别,在并发性能和数据一致性之间做出权衡:
-- 设置隔离级别(MySQL语法)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- MySQL默认
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 不会 | 可能 | 可能 |
| REPEATABLE READ | 不会 | 不会 | 可能 |
| SERIALIZABLE | 不会 | 不会 | 不会 |
自动提交模式
大多数数据库默认开启了自动提交(autocommit),即每条 SQL 语句自动被当作一个事务执行。这意味着每条 INSERT/UPDATE/DELETE 会立即生效且无法回滚。当你需要包裹多个操作为一个事务时,必须显式使用 BEGIN 开启事务,此时自动提交会暂时挂起,直到 COMMIT 或 ROLLBACK。
-- MySQL 关闭自动提交
SET autocommit = 0;
-- 之后每条语句不会自动提交,需要手动 COMMIT 或 ROLLBACK
实战任务
- 开启事务,插入两条学生记录,然后回滚,观察记录是否消失
- 模拟转账:在一个事务中执行扣款和加款,验证原子性
- 使用 SAVEPOINT 实现部分回滚