MySQL: MySQL事务与ACID特性详解

最后更新:2026-08-26

事务保证了数据操作的原子性——要么全成功,要么全失败。

本课讲解事务的原理和使用。

100%
graph TB
    A[START TRANSACTION] --> B[执行SQL操作]
    B --> C{是否成功?}
    C -->|全部成功| D[COMMIT 提交]
    C -->|部分失败| E[ROLLBACK 回滚]
    B --> F[SAVEPOINT 保存点]
    F --> G[ROLLBACK TO sp]
    G --> B
    D --> H[数据持久化]
    E --> I[数据恢复到事务前]

1. 你将学到


2. 转账的真实故事

(1) 痛点:转账中途失败

A 转 100 元给 B:

SQL
UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- 成功
-- 此时系统崩溃
UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- 未执行

结果:A 少了 100,B 没收到——钱凭空消失。

(2) 事务的解法

SQL
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;  -- 两条都成功才提交

3. ACID 特性

特性 说明 实现方式
Atomicity 原子性 事务是不可分割的工作单元 undo log
Consistency 一致性 事务前后数据保持一致 应用层+约束
Isolation 隔离性 并发事务互不干扰 锁+MVCC
Durability 持久性 提交后数据永久保存 redo log

4. 事务操作

▶ 示例:基本事务

SQL
-- 开始事务
START TRANSACTION;

-- 执行操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 提交事务
COMMIT;

-- 或回滚事务
ROLLBACK;
▶ 试一试

▶ 示例:SAVEPOINT 保存点

SQL
START TRANSACTION;

INSERT INTO orders (customer_id, amount) VALUES (1, 100);
SAVEPOINT sp1;

INSERT INTO order_items (order_id, product_id) VALUES (LAST_INSERT_ID(), 1);
SAVEPOINT sp2;

-- 回滚到 sp1(保留第一条 INSERT)
ROLLBACK TO sp1;

-- 提交(只保留第一条 INSERT)
COMMIT;
▶ 试一试

5. 自动提交

▶ 示例:AUTOCOMMIT

SQL
-- 查看自动提交状态
SELECT @@autocommit;

-- 关闭自动提交
SET autocommit = 0;

-- 开启自动提交
SET autocommit = 1;
▶ 试一试
autocommit 说明
1(默认) 每条语句自动提交
0 需要手动 COMMIT

6. 事务隔离级别

隔离级别 脏读 不可重复读 幻读 性能
READ UNCOMMITTED 最高
READ COMMITTED
REPEATABLE READ(默认)
SERIALIZABLE 最低

▶ 示例:设置隔离级别

SQL
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
▶ 试一试

7. 并发问题演示

(1) 脏读

SQL
-- 事务A
START TRANSACTION;
UPDATE accounts SET balance = 1000 WHERE id = 1;
-- 未提交

-- 事务B(READ UNCOMMITTED)
SELECT balance FROM accounts WHERE id = 1;  -- 读到 1000(脏数据)

-- 事务A
ROLLBACK;  -- 回滚

-- 事务B读到的数据是无效的

(2) 不可重复读

SQL
-- 事务A
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1;  -- 读到 500

-- 事务B
UPDATE accounts SET balance = 1000 WHERE id = 1;
COMMIT;

-- 事务A
SELECT balance FROM accounts WHERE id = 1;  -- 读到 1000(不一致)
COMMIT;

❓ 常见问题

Q MySQL 默认隔离级别?
A REPEATABLE READ(可重复读),使用 MVCC + 间隙锁实现。
Q 事务不提交会怎样?
A 锁一直持有,其他事务可能等待超时。
Q DDL 能回滚吗?
A 不能,DDL 自动提交无法回滚。
Q 隐式提交什么意思?
A DDL 语句(CREATE/ALTER/DROP)执行时会自动 COMMIT 当前事务,这就是隐式提交。
Q 大事务有什么风险?
A 锁持有时间长、undo log 膨胀、主从延迟增大。建议拆分为小事务。

📖 小节


📝 作业

  1. 基础题(难度⭐):编写一个转账事务,从账户 A 转 100 到账户 B。

  2. 进阶题(难度⭐⭐):使用 SAVEPOINT 实现部分回滚。

  3. 挑战题(难度⭐⭐⭐):演示不可重复读问题,并用 REPEATABLE READ 隔离级别解决。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏