事务与隔离级别

事务把一组操作打包成「全有或全无」的单元,是保证数据正确性的核心机制。理解隔离级别与并发异常,才能在正确性与性能之间做出取舍。

ACID 再回顾

特性保证方式
原子性 Aundo log:回滚未提交的修改
一致性 C约束 + 应用逻辑 + 事务共同保证
隔离性 I锁 + MVCC
持久性 Dredo log / WAL:崩溃后可恢复

值得一提的是:一致性是目的,原子性、隔离性、持久性只是手段

事务控制

BEGIN;                                  -- 开启事务

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;                                 -- 提交;出错则 ROLLBACK
tx, err := db.BeginTx(ctx, nil)
if err != nil {
    return err
}
defer tx.Rollback() // 已提交时 Rollback 是空操作

if _, err := tx.ExecContext(ctx,
    "UPDATE accounts SET balance = balance - ? WHERE id = ?", 100, 1); err != nil {
    return err
}
if _, err := tx.ExecContext(ctx,
    "UPDATE accounts SET balance = balance + ? WHERE id = ?", 100, 2); err != nil {
    return err
}
return tx.Commit()

并发异常

异常现象
脏读读到了别的事务未提交的数据
不可重复读同一事务内两次读同一行,结果不同(他人更新并提交)
幻读同一事务内两次同样条件的范围查询,行数不同(他人插入并提交)
丢失更新两个事务基于同一旧值更新,后者覆盖前者

四种隔离级别

隔离级别脏读不可重复读幻读
读未提交 Read Uncommitted可能可能可能
读已提交 Read Committed可能可能
可重复读 Repeatable Read可能*
串行化 Serializable

* MySQL 的 InnoDB 在可重复读级别通过 Next-Key Lock(间隙锁) 很大程度避免了幻读。

-- 查看当前隔离级别(MySQL 8)
SELECT @@transaction_isolation;

-- 会话级设置
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Tip

隔离级别越强,一致性越好,但并发度越低。多数互联网业务使用 读已提交(RC);MySQL 默认是可重复读(RR),许多团队会显式改为 RC 以减少间隙锁竞争。金融账务等强一致场景才上串行化。

悲观锁与乐观锁

悲观锁:假设会冲突,先加锁再操作。

BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 加排他锁
UPDATE accounts SET balance = balance + 10 WHERE id = 1;
COMMIT;

乐观锁:假设不冲突,提交时用版本号校验。

UPDATE products
SET stock = stock - 1, version = version + 1
WHERE id = 100 AND version = 7;   -- 影响行数为 0 说明版本过期,重试
方案适用特点
悲观锁冲突频繁、临界区短阻塞等待,可能死锁
乐观锁冲突较少、读多写少无锁、需重试逻辑

MVCC:多版本并发控制

MVCC 让读不加锁、读写不阻塞。其核心是为每行保存多个版本,读操作看到事务开始时的快照:

  • 每行隐含 trx_id(最后修改它的事务)与 roll_pointer(指向 undo log 中的旧版本)。
  • 读取时沿版本链回溯,找到对当前事务可见的版本。
  • 可见性由 Read View 判定:只能看到「已提交且早于本次快照」的版本。

这解释了为什么 RR 级别下同一事务的多次读结果一致(始终用同一个 Read View),而 RC 级别每次读都会重建 Read View。

Warning

MVCC 只对快照读(普通 SELECT)生效。SELECT ... FOR UPDATEUPDATEDELETE当前读仍需加锁,理解这一点是排查锁等待与死锁的关键。

小结

  • ACID 中一致性是目标,A/I/D 是实现手段。
  • 隔离级别是「一致性 vs 并发度」的权衡,互联网业务常用 RC。
  • 悲观锁防冲突,乐观锁省开销;按冲突频率选择。
  • MVCC 让快照读免锁,但当前读仍会加锁。