MySQL 第九天:事务隔离级别与锁机制实战(全解析)
聚焦 事务 ACID 特性、4 大隔离级别、InnoDB 锁体系、MVCC 原理,覆盖面试 90% 高频考点,结合实战案例吃透底层逻辑。
一、事务基础:ACID 四大特性(必背)
| 特性 | 含义 | InnoDB 实现机制 |
|---|---|---|
| 原子性(Atomicity) | 事务是不可分割的最小单元,要么全成功,要么全回滚 | Undo Log(回滚日志):记录修改前的数据,回滚时按 Undo Log 恢复数据 |
| 一致性(Consistency) | 事务前后数据完整性、业务规则保持一致 | 原子性 + 隔离性 + 持久性共同保证;约束(主键 / 唯一索引 / 外键)兜底 |
| 隔离性(Isolation) | 多个事务并发操作时,彼此互不干扰 | MVCC + 锁机制(共享锁 / 排他锁 / 间隙锁) |
| 持久性(Durability) | 事务提交后,数据永久保存,不会因宕机丢失 | Redo Log(重做日志):记录修改操作,宕机后重放恢复数据;配合innodb_flush_log_at_trx_commit刷盘策略 |
2. 事务操作语法
-- 1. 开启事务
BEGIN; / START TRANSACTION;
-- 2. 提交事务(持久化)
COMMIT;
-- 3. 回滚事务(撤销所有操作)
ROLLBACK;
-- 4. 设置事务隔离级别(会话级/全局级)
-- 会话级(当前连接有效)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 全局级(所有新连接有效)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 5. 查看当前隔离级别
SELECT @@transaction_isolation;
二、核心难点:事务隔离级别与并发问题
| 问题 | 定义 | 通俗案例 |
|---|---|---|
| 脏读(Dirty Read) | 读到其他事务未提交的临时数据,数据无效 | 事务 A 把用户余额从 1000 改 2000(未提交),事务 B 读到 2000;事务 A 回滚,事务 B 拿到 “脏数据” |
| 不可重复读(Non-Repeatable Read) | 同一事务内多次读取同一行数据,结果不一致 | 事务 A 第一次查余额 1000,事务 B 修改并提交为 2000,事务 A 再查变成 2000 |
| 幻读(Phantom Read) | 同一事务内多次查询同一范围,返回的记录数不一致 | 事务 A 查 “年龄> 20” 的用户(3 条),事务 B 插入 1 条符合条件的记录并提交,事务 A 再查变成 4 条 |
2. MySQL 4 大隔离级别(由低到高,面试必问)
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制 | 适用场景 |
|---|---|---|---|---|---|
| READ UNCOMMITTED(读未提交) | ❌ | ❌ | ❌ | 无锁,直接读最新数据 | 几乎不用(仅允许极低成本的临时统计) |
| READ COMMITTED(读已提交) | ✅ | ❌ | ❌ | MVCC 快照读(每次查询生成新快照)+ 行锁 | 多数互联网业务(如电商详情页),接受不可重复读,追求高并发 |
| REPEATABLE READ(可重复读) | ✅ | ✅ | ✅(InnoDB 解决) | MVCC 一致性快照(事务启动时生成全局快照)+ Next-Key Lock(行锁 + 间隙锁) | MySQL 默认,金融 / 订单等强一致性场景 |
| SERIALIZABLE(串行化) | ✅ | ✅ | ✅ | 表级锁(读加共享锁,写加排他锁),事务串行执行 | 极端场景(如银行对账),性能最差,几乎不用 |
三、底层原理:MVCC 多版本并发控制(面试深挖点)
MVCC 是 InnoDB 实现非阻塞读(读不加锁)的核心,解决隔离性问题的同时保证高并发。

struct ReadView {
trx_id_t m_creator_trx_id; // 创建该视图的事务ID(本事务修改的数据可见)
trx_ids_t m_ids; // 生成视图时,所有**未提交**的事务ID列表
trx_id_t m_low_limit_id; // 下一个待分配的事务ID(大于该值的事务均不可见)
trx_id_t m_up_limit_id; // m_ids中的最小值(小于该值的事务均已提交,可见)
}
四、InnoDB 锁机制(锁粒度 + 类型 + 实战)
锁是控制并发写、解决幻读的关键,InnoDB 锁体系按粒度和类型分类,核心掌握以下 4 类:
| 锁类型 | 定义 | 特点 | 适用场景 |
|---|---|---|---|
| 行锁(Record Lock) | 锁定单行数据 | 粒度最细,并发性能高;仅锁定索引记录 | 高并发更新(如订单修改) |
| 间隙锁(Gap Lock) | 锁定索引之间的间隙(不包含记录本身) | 左开右闭;仅 RR 级别生效;防止插入 | 解决当前读幻读 |
| Next-Key Lock(临键锁) | 行锁 + 间隙锁的组合 | 左开右闭区间锁;RR 级别默认锁算法 | 范围查询防幻读 |
| 表锁(Table Lock) | 锁定整张表 | 粒度最粗,并发性能低;无索引时退化为表锁 | 全表更新 / DDL 操作 |
2. 按读写类型分类
| 锁类型 | 别名 | 作用 | 互斥关系 |
|---|---|---|---|
| 共享锁(S Lock) | 读锁 | 允许多个事务同时读,禁止写 | 与 S 锁兼容,与 X 锁互斥 |
| 排他锁(X Lock) | 写锁 | 独占数据,禁止其他事务读写 | 与 S/X 锁均互斥 |
-- 加共享锁(读锁,其他事务可读不可写)
SELECT * FROM table WHERE id = 1 LOCK IN SHARE MODE;
-- 加排他锁(写锁,其他事务不可读不可写)
SELECT * FROM table WHERE id = 1 FOR UPDATE;

五、实战案例:事务并发与锁冲突模拟
案例 1:脏读演示(READ UNCOMMITTED 级别)
-- 会话A(设置隔离级别为读未提交)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
UPDATE account SET balance = 2000 WHERE id = 1; -- 未提交
-- 会话B(同一时间执行)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
SELECT balance FROM account WHERE id = 1; -- 读到2000(脏读)
COMMIT;
-- 会话A回滚
ROLLBACK;
案例 2:RR 级别解决幻读(当前读)
-- 初始化数据
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(20), age INT);
INSERT INTO user VALUES (1, '李四', 20), (2, '王五', 25);
-- 事务A(RR级别,当前读)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT * FROM user WHERE age > 20 FOR UPDATE; -- 查到id=2(1条)
-- 事务B(同一时间执行)
INSERT INTO user VALUES (3, '赵六', 22); -- 被阻塞,等待事务A提交
COMMIT;
-- 事务A提交
COMMIT;


浙公网安备 33010602011771号