MySQL 事务与锁机制深入剖析
MySQL 事务和锁是保证数据一致性的核心机制,也是面试高频考点,更是实际开发中死锁、性能问题的根源所在。本文从原理到实践,帮你彻底搞懂 MySQL 的事务和锁。
一、ACID 特性详解
- 原子性(Atomicity):事务内的操作要么全部成功,要么全部回滚。由 undo log 保证。
- 一致性(Consistency):事务执行前后数据库处于合法状态,是事务的最终目标。
- 隔离性(Isolation):多个事务并发执行时互不干扰。由 MVCC + 锁实现。
- 持久性(Durability):事务提交后数据永久保存。由 redo log 和刷盘策略保证。
二、四种隔离级别与问题
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED | ✗ | ✓ | ✓ |
| REPEATABLE READ(默认) | ✗ | ✗ | 部分解决 |
| SERIALIZABLE | ✗ | ✗ | ✗ |
InnoDB 默认使用 REPEATABLE READ,并通过 Next-Key Lock 解决大多数幻读问题。
三、MVCC 多版本并发控制
MVCC 让读写操作互不阻塞。核心机制:
- 每行数据有隐藏字段:trx_id(最后修改事务ID)和 roll_pointer(undo log 指针)
- 每个事务开始时创建 Read View(一致性视图),记录当前活跃事务列表
- 读取数据时,通过 undo log 链找到对当前事务可见的版本
- SELECT 不加锁(快照读),通过 Read View 实现一致性读
四、锁的分类
按粒度:表锁(开销小,并发低)、行锁(开销大,并发高,InnoDB 默认)
按类型:
- 共享锁(S锁):SELECT … LOCK IN SHARE MODE,允许多个事务同时读
- 排他锁(X锁):SELECT … FOR UPDATE / INSERT / UPDATE / DELETE,独占
- 意向锁(IS/IX):表级锁,表明事务意图加行锁,避免逐行检查冲突
- 间隙锁(Gap Lock):锁定索引间的间隙,防止幻读
- 临键锁(Next-Key Lock):行锁 + 间隙锁,InnoDB 的默认行锁形式
五、死锁分析与预防
死锁是两个事务互相等待对方释放锁。InnoDB 会自动检测并回滚代价较小的事务。
预防策略:
- 保持固定的加锁顺序(所有事务按相同顺序访问表/行)
- 减小事务粒度,尽快提交事务
- 使用 SELECT … FOR UPDATE 时确保有合适索引,避免全表锁
- 业务允许时降低隔离级别(RC 不使用间隙锁,死锁概率更低)
查看死锁信息:SHOW ENGINE INNODB STATUS\G
六、常用锁相关命令
-- 查看当前锁等待 SELECT * FROM information_schema.INNODB_LOCK_WAITS; -- 查看事务列表 SELECT * FROM information_schema.INNODB_TRX; -- 查看锁信息(MySQL 8.0) SELECT * FROM performance_schema.data_locks; -- 手动提交/回滚 BEGIN; -- 或 START TRANSACTION COMMIT; ROLLBACK;
总结
理解 MVCC 是读写不冲突的关键,理解锁机制是解决死锁和性能问题的基础。实际开发中要尽量缩短事务时长,合理选择隔离级别,为 WHERE 条件字段加索引(避免锁升级为表锁),这三点能解决 80% 的锁相关问题。