MySQL MVCC(多版本并发控制)详解

发布于:2025-06-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. 什么是MVCC?

MVCC(Multi-Version Concurrency Control,多版本并发控制) 是 MySQL(InnoDB引擎)实现高并发访问的核心机制之一。它通过在同一时刻保存数据的多个版本,使得:

  • 读操作不阻塞写操作
  • 写操作不阻塞读操作
  • 提高数据库的并发性能

📌 对比锁机制

  • 传统锁(如行锁)会导致读写冲突
  • MVCC 通过数据多版本实现非阻塞读

2. MVCC 核心原理

2.1 版本链与隐藏字段

InnoDB 每行记录包含3个隐藏字段

  1. DB_TRX_ID(6字节):最近修改该行的事务ID
  2. DB_ROLL_PTR(7字节):回滚指针,指向Undo Log中的旧版本
  3. DB_ROW_ID(6字节):行ID(无主键时自动生成)
-- 实际存储结构(伪代码)
row = {
    id: 1, 
    name: "Alice",
    DB_TRX_ID: 100, 
    DB_ROLL_PTR: 0x123456, 
    DB_ROW_ID: 1
}

2.2 Undo Log(回滚日志)

  • 存储数据被修改前的历史版本,形成版本链
  • 用于:
    • 事务回滚(ROLLBACK)
    • MVCC 读一致性视图
DB_ROLL_PTR
roll_ptr
当前行
Undo Log v1
Undo Log v2

2.3 ReadView(一致性视图)

决定事务能看到哪个版本的数据,包含:

  • creator_trx_id:创建该ReadView的事务ID
  • m_ids:生成ReadView时活跃的事务ID列表
  • min_trx_id:m_ids中的最小ID
  • max_trx_id:系统下一个待分配的事务ID

3. MVCC 工作流程

3.1 读操作(SELECT)

通过 ReadView 判断数据可见性:

  1. 如果 DB_TRX_ID < min_trx_id:说明数据在ReadView创建前已提交 → 可见
  2. 如果 DB_TRX_ID >= max_trx_id:说明数据在ReadView创建后修改 → 不可见
  3. 如果 min_trx_id <= DB_TRX_ID < max_trx_id
    • DB_TRX_ID ∈ m_ids:说明事务未提交 → 不可见
    • 否则 → 可见

3.2 写操作(UPDATE/DELETE)

  1. 新数据写入时,旧数据进入 Undo Log
  2. 更新 DB_TRX_ID 为当前事务ID
  3. 更新 DB_ROLL_PTR 指向旧版本

4. MVCC 与隔离级别

不同隔离级别下 MVCC 的行为:

隔离级别 MVCC 行为
READ UNCOMMITTED 直接读最新数据(不适用MVCC)
READ COMMITTED (RC) 每次SELECT生成新ReadView,能看到其他事务已提交的修改
REPEATABLE READ (RR) 第一次SELECT时生成ReadView,后续沿用该视图(避免不可重复读)
SERIALIZABLE 退化为加锁(不适用MVCC)

5. 实战案例分析

场景:事务并发修改同一条数据

-- 初始数据
INSERT INTO users (id, name) VALUES (1, 'Alice');

-- 事务1(TRX_ID=100)
BEGIN;
UPDATE users SET name = 'Bob' WHERE id = 1;

-- 事务2(TRX_ID=200,在RC隔离级别下)
BEGIN;
SELECT name FROM users WHERE id = 1; -- 看到 'Alice'(ReadView在事务1提交前生成)
COMMIT;

-- 事务1提交后
COMMIT;

-- 事务3(TRX_ID=300)
BEGIN;
SELECT name FROM users WHERE id = 1; -- 看到 'Bob'(事务1已提交)

6. MVCC 的优缺点

优点

高并发:读写不互相阻塞
避免锁竞争:减少死锁概率
快照读:支持一致性非锁定读

缺点

额外存储:需维护Undo Log和历史版本
清理成本:需要Purge线程清理旧版本数据


7. 关键参数优化

-- 查看InnoDB MVCC相关状态
SHOW ENGINE INNODB STATUS;

-- 控制Undo Log保留时间(默认0,表示由purge线程自动管理)
SET GLOBAL innodb_undo_log_truncate = ON;
SET GLOBAL innodb_undo_retention = 3600; -- 保留1小时

总结

  1. MVCC 通过版本链 + ReadView 实现非阻塞读
  2. RC/RR 隔离级别依赖 MVCC 实现不同的一致性视图
  3. Undo Log 是 MVCC 的基石,存储历史版本数据
  4. 合理设置隔离级别和undo保留时间可优化性能

理解 MVCC 能帮助你设计更高并发的数据库应用! 🚀


网站公告

今日签到

点亮在社区的每一天
去签到