MySQL 事务与锁机制
ACID 特性
| 特性 | 说明 |
|---|---|
| 原子性 (Atomicity) | 事务要么全部成功,要么全部回滚 |
| 一致性 (Consistency) | 事务前后数据完整性约束不变 |
| 隔离性 (Isolation) | 并发事务之间互不干扰 |
| 持久性 (Durability) | 提交后数据永久保存(redo log) |
四种隔离级别
SELECT @@transaction_isolation; -- 查看当前级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置
| 级别 | 脏读 | 不可重复读 | 幻读 | 默认 |
|---|---|---|---|---|
| READ UNCOMMITTED | 有 | 有 | 有 | - |
| READ COMMITTED | 无 | 有 | 有 | Oracle |
| REPEATABLE READ | 无 | 无 | 部分 | MySQL |
| SERIALIZABLE | 无 | 无 | 无 | - |
MVCC 多版本并发控制
InnoDB 通过 undo log + ReadView 实现 MVCC:
- 每行有隐藏列 trx_id(事务ID)和 roll_pointer
- UPDATE 时旧版本写入 undo log
- SELECT 时根据 ReadView 可见性规则判断哪些版本可见
- READ COMMITTED:每次 SELECT 生成新 ReadView
- REPEATABLE READ:事务开始时生成 ReadView
InnoDB 锁类型
行锁 (Record Lock)
-- 排他锁 SELECT * FROM article WHERE id = 1 FOR UPDATE; -- 共享锁 SELECT * FROM article WHERE id = 1 LOCK IN SHARE MODE;
间隙锁 (Gap Lock)
REPEATABLE READ 级别特有,锁定索引间隙,防止其他事务在间隙中 INSERT,用于防止幻读。
Next-Key Lock
行锁 + 间隙锁的组合,是 InnoDB 默认的锁定方式。
表锁
LOCK TABLES article READ; UNLOCK TABLES;
锁升级陷阱
-- 索引失效 → 行锁升级为表锁! SELECT * FROM article WHERE title LIKE '%MySQL%' FOR UPDATE;
-- 隐式锁:UPDATE/DELETE/INSERT 自动加锁 UPDATE article SET status = 1 WHERE id = 1; -- 自动加 X 行锁
死锁排查
-- 查看 InnoDB 状态(含最近死锁信息) SHOW ENGINE INNODB STATUS;
-- 查看当前事务 SELECT * FROM information_schema.INNODB_TRX;
避免死锁的最佳实践:
- 以相同顺序访问表和行
- 缩短事务,尽快提交
- WHERE 条件尽量走索引(减少锁范围)
- 应用层加重试机制(Spring @Retryable)
- 大事务拆分:分批处理 + 每批提交