在开发和运维 MySQL 数据库的过程中,事务(Transaction) 是绕不开的核心知识点,它是保证数据库数据安全、一致、可靠的基石。无论是电商下单、银行转账、支付结算,还是日常的业务数据操作,都离不开事务的支撑。
这篇文章会从事务的定义、四大特性(ACID)、隔离级别、并发问题、事务语法、实战案例、底层原理等维度,把 MySQL 事务讲得明明白白,新手也能轻松看懂、直接用。
一、什么是 MySQL 事务?
简单来说:事务是一组不可分割的数据库操作集合,要么全部执行成功,要么全部执行失败,不会出现中间状态。
举个最经典的例子:银行转账A 账户给 B 账户转 100 元,数据库需要执行两步操作:
- A 账户扣 100 元
- B 账户加 100 元
这两步必须同时成功 或者同时失败:
- 如果 A 扣钱了、B 没加钱 → 数据错乱,用户损失
- 如果 A 没扣钱、B 加钱了 → 银行损失
事务就是用来杜绝这种中间状态,保证数据绝对可靠。
二、事务的四大特性:ACID
事务的核心就是 ACID 四大特性,这是面试必问、开发必懂的知识点。
1. 原子性(Atomicity)
定义 :事务是最小的执行单位,不可分割。
- 事务中的所有 SQL,要么全部执行成功,要么全部回滚(撤销)。
- 只要有一步失败,整个事务都作废,数据回到执行前的状态。
2. 一致性(Consistency)
定义 :事务执行前后,数据库的完整性约束不被破坏。
- 转账前后,A 和 B 的总金额不变。
- 数据始终符合业务规则,不会出现非法、错乱的数据。
3. 隔离性(Isolation)
定义 :多个事务并发执行时,互相不干扰,一个事务的中间状态对其他事务不可见。
- 隔离性通过事务隔离级别实现,后面会详细讲。
4. 持久性(Durability)
定义 :一旦事务提交成功,对数据的修改是永久的。
- 即使数据库宕机、重启,数据也不会丢失。
- 依靠 MySQL 的 redo log 实现持久化。
三、事务的并发问题(不隔离会怎样?)
如果多个事务同时操作同一份数据,不做隔离,会出现 4 种经典问题:
1. 脏读(Dirty Read)
一个事务读取到了另一个未提交事务修改的数据。
- 例子:事务 1 修改数据但未提交,事务 2 读到了这个临时数据,结果事务 1 回滚了 → 事务 2 读到的是 "脏数据"。
2. 不可重复读(Non-Repeatable Read)
一个事务内,多次读取同一行数据,结果不一致。
- 原因:其他事务在这期间修改并提交了这行数据。
3. 幻读(Phantom Read)
一个事务内,多次查询的结果集行数不一致。
- 原因:其他事务在这期间插入 / 删除了符合条件的数据。
4. 丢失更新(Lost Update)
两个事务同时修改同一数据,后提交的事务覆盖了先提交的修改。
四、事务的四大隔离级别
MySQL 提供了 4 种隔离级别,用来解决上面的并发问题,级别从低到高:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
|---|---|---|---|---|
| 读未提交(READ UNCOMMITTED) | ✅ 允许 | ✅ 允许 | ✅ 允许 | 最高 |
| 读已提交(READ COMMITTED) | ❌ 禁止 | ✅ 允许 | ✅ 允许 | 高 |
| 可重复读(REPEATABLE READ) | ❌ 禁止 | ❌ 禁止 | ⚠️ 部分解决 | 中 |
| 串行化(SERIALIZABLE) | ❌ 禁止 | ❌ 禁止 | ❌ 禁止 | 最低 |
重点说明:
- MySQL 默认隔离级别 :可重复读(REPEATABLE READ)
- InnoDB 存储引擎在 可重复读级别 下,通过 MVCC + 间隙锁 基本解决了幻读问题。
- 隔离级别越高,数据越安全,但并发性能越差。
- 生产环境推荐使用:读已提交 或 可重复读。
五、MySQL 事务基本语法
1. 开启事务
sql
START TRANSACTION;
-- 或者简写
BEGIN;
2. 提交事务(永久生效)
sql
COMMIT;
3. 回滚事务(撤销所有操作)
sql
ROLLBACK;
4. 设置事务隔离级别
sql
-- 会话级别(当前连接生效)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 全局级别(所有新连接生效)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
5. 查看当前隔离级别
sql
SELECT @@transaction_isolation;
六、实战案例:银行转账(事务完整演示)
1. 创建测试表
sql
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
balance DECIMAL(10,2)
);
INSERT INTO account(name, balance) VALUES
('张三', 1000.00),
('李四', 1000.00);
2. 正常转账(提交事务)
sql
-- 开启事务
BEGIN;
-- 1. 张三扣 100
UPDATE account SET balance = balance - 100 WHERE name = '张三';
-- 2. 李四加 100
UPDATE account SET balance = balance + 100 WHERE name = '李四';
-- 确认无误,提交
COMMIT;
执行后:张三 900,李四 1100 ✅
3. 异常转账(回滚事务)
sql
BEGIN;
UPDATE account SET balance = balance - 100 WHERE name = '张三';
-- 模拟异常(比如程序报错、网络中断)
-- 直接回滚,所有操作作废
ROLLBACK;
执行后:数据回到原来的状态,没有任何修改 ✅
七、事务的底层原理(进阶)
想真正吃透事务,必须了解它的底层实现机制:
1. redo log(重做日志)
- 保证持久性
- 记录 "修改了什么数据",数据库宕机重启后,通过 redo log 恢复数据
2. undo log(回滚日志)
- 保证原子性
- 记录修改前的数据,事务回滚时,用 undo log 恢复数据
3. MVCC(多版本并发控制)
- 保证隔离性
- 实现无锁读写,提升并发性能
- 是 MySQL 高效处理并发事务的核心
八、事务使用注意事项(生产必看)
-
事务要短小精悍不要在事务里执行耗时操作(远程调用、sleep、大量计算),否则会导致锁等待、性能暴跌。
-
避免长事务长事务会占用大量 undo log,导致数据库性能下降。
-
所有更新操作必须加事务尤其是涉及多表、多行的业务逻辑。
-
不要自动提交 生产环境建议关闭自动提交:
SET autocommit = 0; -
异常必须回滚 程序捕获异常时,一定要执行
ROLLBACK。
九、总结
- 事务:一组操作,要么全成,要么全败。
- ACID:原子性、一致性、隔离性、持久性,事务的灵魂。
- 并发问题:脏读、不可重复读、幻读、丢失更新。
- 隔离级别 :MySQL 默认 可重复读,兼顾安全与性能。
- 核心命令 :
BEGIN→ 执行 SQL →COMMIT/ROLLBACK。 - 底层:redo log、undo log、MVCC 共同支撑事务。
掌握 MySQL 事务,你就能写出安全、稳定、高并发的数据库程序,这是后端开发的核心基本功。