MySQL 中的 事务(Transaction) 是数据库操作的一个重要概念,它确保了数据在并发访问和系统故障时的一致性和可靠性。
✅ 一、事务的四大特性:ACID
ACID 是事务的基本特征,也是关系型数据库的核心原则。
特性 | 含义 | 简要说明 |
---|---|---|
A - Atomicity(原子性) | 事务是一个不可分割的工作单位,要么全部成功,要么全部失败。 | 如果事务中某条 SQL 执行失败,整个事务都会回滚。 |
C - Consistency(一致性) | 事务必须使数据库从一个一致状态变换到另一个一致状态。 | 事务执行前后,数据库完整性约束(如主键、外键等)不能被破坏。 |
I - Isolation(隔离性) | 多个事务并发执行时,彼此之间应该互不干扰。 | 不同的隔离级别决定了事务之间的可见性。 |
D - Durability(持久性) | 事务一旦提交,对数据库的修改就是永久性的。 | 即使系统崩溃,已提交的事务也不会丢失。 |
✅ 二、事务的四种隔离级别(Isolation Levels)
不同隔离级别控制的是事务之间读取未提交数据或并发写入时的行为,主要解决以下三个问题:
- 脏读(Dirty Read)
- 不可重复读(Non-repeatable Read)
- 幻读(Phantom Read)
隔离级别 | 脏读 | 不可重复读 | 幻读 | 加锁读 |
---|---|---|---|---|
READ UNCOMMITTED | ✅ 允许 | ✅ 允许 | ✅ 允许 | ❌ |
READ COMMITTED | ❌ 禁止 | ✅ 允许 | ✅ 允许 | ❌ |
REPEATABLE READ | ❌ 禁止 | ❌ 禁止 | ❌ 禁止(MySQL InnoDB 特殊处理) | ✅ 支持 |
SERIALIZABLE | ❌ 禁止 | ❌ 禁止 | ❌ 禁止 | ✅ 支持 |
🔧 设置事务隔离级别的方法:
-- 查看当前会话/全局的隔离级别
SELECT @@tx_isolation; -- MySQL 5.7 及之前
SELECT @@transaction_isolation; -- MySQL 8.0+
-- 设置隔离级别(会话级)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置隔离级别(全局级)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
✅ 三、事务隔离级别是怎么实现的?
InnoDB 存储引擎通过以下机制来实现不同的事务隔离级别:
🧠 1. MVCC(多版本并发控制)
- MVCC 主要用于实现 读已提交(Read Committed) 和 可重复读(Repeatable Read) 的隔离级别。
- 它通过 Undo Log + Read View 来提供非锁定一致性读。
核心组件:
- Undo Log(撤销日志):保存数据的历史版本。
- Read View(读视图):决定当前事务能看到哪些版本的数据。
实现效果:
- 事务看到的是一个“快照”,不会被其他事务的未提交更改影响。
- 在
REPEATABLE READ
下,同一个事务多次查询结果保持一致。 - 在
READ COMMITTED
下,每次查询都生成新的 Read View,看到最新的已提交数据。
🧠 2. 锁机制(Locking)
对于更高隔离级别(如 SERIALIZABLE
),InnoDB 使用锁来防止并发冲突。
类型 | 描述 |
---|---|
共享锁(S Lock) | 读锁,允许多个事务同时读取同一资源,但阻止写操作。 |
排他锁(X Lock) | 写锁,阻止其他事务读写该资源。 |
间隙锁(Gap Lock) | 锁定索引记录之间的“间隙”,防止插入新记录(用于防止幻读)。 |
临键锁(Next-Key Lock) | Gap Lock + Record Lock,是 InnoDB 默认使用的锁类型。 |
示例:
START TRANSACTION;
SELECT * FROM user WHERE id = 1 FOR UPDATE; -- 加 X 锁
🧠 3. InnoDB 如何处理幻读?
虽然标准上 REPEATABLE READ
允许幻读,但 InnoDB 在 RR 级别下通过 Next-Key Lock 避免了幻读。
例如:
START TRANSACTION;
SELECT * FROM user WHERE age BETWEEN 20 AND 30; -- 查询范围
-- 此时另一个事务试图插入 age=25 的记录会被阻塞,直到前一个事务提交或回滚
🧠 4. Redo Log / Undo Log 的作用
日志类型 | 作用 | 对应事务特性 |
---|---|---|
Redo Log | 记录物理页的修改,用于崩溃恢复 | 持久性(Durability) |
Undo Log | 记录逻辑修改,用于事务回滚和 MVCC | 原子性(Atomicity)、一致性(Consistency) |
✅ 四、不同隔离级别的行为对比
隔离级别 | 实现机制 | 是否加锁 | 能否避免 |
---|---|---|---|
READ UNCOMMITTED | 直接读取最新数据 | ❌ | ❌脏读、❌不可重复读、❌幻读 |
READ COMMITTED | MVCC(每语句新 Read View) | ❌ | ✅脏读、❌不可重复读、❌幻读 |
REPEATABLE READ | MVCC(事务开始固定 Read View)+ Next-Key Lock | ❌/✅ | ✅脏读、✅不可重复读、✅幻读 |
SERIALIZABLE | 所有 SELECT 自动加 S 锁 | ✅ | ✅脏读、✅不可重复读、✅幻读 |
✅ 五、默认隔离级别是什么?
- MySQL 默认隔离级别为:
REPEATABLE READ
- 可以使用如下命令查看:
SELECT @@global.transaction_isolation, @@session.transaction_isolation;
✅ 六、如何选择合适的隔离级别?
应用场景 | 推荐级别 | 原因 |
---|---|---|
高并发读写系统(如电商下单) | REPEATABLE READ | InnoDB 默认支持,性能与一致性平衡 |
强一致性要求(如金融转账) | SERIALIZABLE | 绝对一致性,但牺牲并发性能 |
数据分析类应用 | READ COMMITTED | 保证读到已提交数据即可 |
快速读取无一致性要求 | READ UNCOMMITTED | 极端情况才用,容易出错 |
✅ 七、补充:InnoDB 是如何实现事务的?
InnoDB 使用 事务日志(Redo Log & Undo Log) 和 锁机制 来实现完整的事务支持。
组件 | 功能 |
---|---|
Redo Log | 提供 crash-safe,确保事务持久性 |
Undo Log | 支持事务回滚和 MVCC |
Lock System | 控制并发访问,实现隔离性 |
Transaction Manager | 管理事务生命周期(开启、提交、回滚) |