MySQL InnoDB 的事务机制是其最核心的特性之一,它通过严格遵循 ACID 模型,为数据提供了可靠的并发控制和故障恢复能力。下面从多个维度详细介绍 InnoDB 的事务。
1. 事务的定义
事务是一组原子性的 SQL 操作,要么全部执行成功,要么全部不执行。在 InnoDB 中,事务可以显式开启和结束,也可以隐式地通过自动提交模式管理。
2. ACID 属性与 InnoDB 的实现
| 属性 | 含义 | InnoDB 实现方式 |
|---|---|---|
| 原子性 | 事务中的操作要么全部完成,要么全部回滚 | 通过 undo log 记录修改前的旧值,事务回滚时利用 undo log 恢复数据 |
| 一致性 | 事务前后数据库的完整性约束不被破坏 | 通过原子性、隔离性、持久性共同保证,同时外键约束、触发器、数据类型检查等也发挥作用 |
| 隔离性 | 多个事务并发执行时,相互隔离,不互相干扰 | 通过 MVCC(多版本并发控制) 和 锁机制(行锁、间隙锁、Next-Key 锁)实现不同的隔离级别 |
| 持久性 | 事务一旦提交,其修改永久保存,即使系统崩溃也不丢失 | 通过 redo log 实现。提交时先写 redo log(WAL 技术),崩溃恢复时重放 redo log 确保已提交事务的修改不丢失 |
3. 事务控制语句
sql
sql
-- 显式开启事务
START TRANSACTION; -- 或 BEGIN;
-- 提交事务(永久生效)
COMMIT;
-- 回滚事务(撤销当前事务所有修改)
ROLLBACK;
-- 设置保存点,实现部分回滚
SAVEPOINT sp1;
ROLLBACK TO SAVEPOINT sp1;
RELEASE SAVEPOINT sp1;
-- 设置自动提交模式(默认开启,每条语句自动提交)
SET autocommit = 0; -- 关闭自动提交,需手动 COMMIT
SET autocommit = 1; -- 开启自动提交
4. 事务隔离级别
InnoDB 支持 SQL 标准定义的四种隔离级别,默认使用 REPEATABLE READ。
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 | 读未提交,最低隔离,一般不使用 |
| READ COMMITTED | 不可能 | 可能 | 可能 | Oracle 默认级别,只读已提交数据 |
| REPEATABLE READ | 不可能 | 不可能 | 可能(InnoDB 通过 MVCC + 间隙锁解决) | InnoDB 默认级别,可重复读,避免幻读 |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 | 强制事务串行执行,读加锁,性能最低 |
- 脏读:读到其他事务未提交的数据。
- 不可重复读:同一事务内两次读同一行数据,结果不一致(因其他事务修改并提交)。
- 幻读:同一事务内两次执行相同查询,结果集行数不一致(因其他事务插入或删除)。
设置隔离级别:
sql
sql
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
5. MVCC(多版本并发控制)
InnoDB 通过 MVCC 实现高并发下的非锁定读,使得读操作不阻塞写操作,写操作也不阻塞读操作。
- 实现原理 :每行记录隐藏两个列:
DB_TRX_ID(最近修改的事务 ID)和DB_ROLL_PTR(指向 undo log 中旧版本记录的指针)。 - Read View:事务执行查询时,根据当前系统的活跃事务列表创建一个 Read View,决定哪些版本的数据可见。
- 在 REPEATABLE READ 下:事务首次读取时创建 Read View,直到事务结束都复用该视图,从而保证可重复读。
- 在 READ COMMITTED 下:每条语句执行时都重新创建 Read View,因此每次读取可能看到最新的已提交数据。
MVCC 配合 undo log 使得 InnoDB 在大多数读场景下不需要加锁,显著提升并发性能。
6. 锁机制
InnoDB 使用多种锁来保证事务隔离性,锁粒度以行级为主,兼顾表级。
6.1 锁类型
- 共享锁(S锁) :允许事务读一行,阻止其他事务加排他锁。
SELECT ... LOCK IN SHARE MODE; - 排他锁(X锁) :允许事务读/写一行,阻止其他事务加任何锁。
SELECT ... FOR UPDATE;或 DML 语句自动加 X 锁。
6.2 行锁算法
- Record Lock:锁定单条记录。
- Gap Lock:锁定索引记录之间的间隙(范围),防止幻读。
- Next-Key Lock:Record Lock + Gap Lock 的组合,InnoDB 在 REPEATABLE READ 级别下默认使用,锁定一个范围并包含记录本身,有效防止幻读。
6.3 意向锁
表级锁,用于协调行锁和表锁。当加行锁时,InnoDB 自动给表加意向锁,避免其他事务对整个表加锁时遍历所有行。
7. 并发问题与隔离级别的解决
| 并发问题 | 定义 | 解决方案 |
|---|---|---|
| 脏读 | 读到未提交的数据 | 隔离级别 ≥ READ COMMITTED 时,通过 MVCC 只读已提交版本 |
| 不可重复读 | 同一事务内两次读同一行结果不同 | 隔离级别 ≥ REPEATABLE READ 时,通过 MVCC 的 Read View 复用解决 |
| 幻读 | 同一事务内两次查询结果集行数不同 | REPEATABLE READ 下,InnoDB 使用 Next-Key Lock 锁定范围,防止新数据插入;SERIALIZABLE 下通过表级锁避免 |
8. 事务的自动提交与隐式提交
- 自动提交模式 :默认每个 SQL 语句作为一个事务自动提交。可通过
SET autocommit=0关闭,此时需要显式 COMMIT。 - 隐式提交 :某些语句(如 DDL 语句
CREATE TABLE、ALTER TABLE、TRUNCATE等)会隐式提交当前事务。
9. 总结
InnoDB 的事务机制通过 undo log 保证原子性和 MVCC,redo log 保证持久性,锁 + MVCC 实现隔离性,从而完整支持 ACID。默认隔离级别 REPEATABLE READ 结合 Next-Key Lock 能有效避免幻读,同时保持较高的并发性能。在实际开发中,合理控制事务大小、隔离级别和锁粒度,是保障数据库性能和一致性的关键。