前言
多版本并发控制(mvcc,multi-version concurrency control)是一种实现高并发事务隔离的核心机制。它通过保存数据的多个历史版本,让读写操作不堵塞,从而避免了传统锁机制带来的瓶颈。
1. 核心思想
mvcc 为每个事务提供一个数据快照(snapshot),事务读取的是某个时间点的一致性数据版本,而不是最新的数据,如此一来:
读操作不需要等待写操作释放锁
写操作也不需要等待读操作完成
实现了非阻塞读
2. 关键数据结构
innodb通过undo log + 隐藏字段 + read view实现mvcc。
2.1 undo log
undo log是 mvcc 的版本链基础:
插入:
undo log记录主键,用于回滚时删除删除:标记删除,
undo log记录完整行数据,用于恢复更新:
undo log记录旧值,形成版本链
2.2 隐藏字段
每行记录自动添加,对用户不可见,
innodb自动维护
| 字段名 | 大小 | 作用 |
|---|---|---|
db_trx_id | 6 字节 | 创建该版本的事务id(最后修改此行的事务) |
db_roll_ptr | 7 字节 | 回滚指针,指向undo log的上一个版本 |
db_row_id | 6 字节 | 隐藏主键 |
2.3 read view
read view是事务执行快照读时生成的一致性试图,决定事务能看待哪些版本的数据。
read view包含的关键字段:
| 字段 | 说明 |
|---|---|
creator_trx_id | 创建该read view的事务id |
m_ids | 生成read view时,活跃(未提交)事务id列表 |
min_trx_id | m_ids中的最小值 |
max_trx_id | 生成read view时,系统分配的下一个事务id(全局最大加 1) |
3. 可见性判断规则
当事务读取某行数据时,通过比较该行的db_trx_id与read view来判断可见性:
判断流程(对版本链从上到下遍历): 1. 如果 db_trx_id == creator_trx_id → 可见(自己修改的) 2. 如果 db_trx_id < min_trx_id → 可见(已提交事务修改的) 3. 如果 db_trx_id >= max_trx_id → 不可见(将来事务修改的,未发生) 4. 如果 min_trx_id <= db_trx_id < max_trx_id: - 如果 db_trx_id 在 m_ids 中 → 不可见(未提交事务修改的) - 如果 db_trx_id 不在 m_ids 中 → 可见(已提交事务修改的) 如果不可见,就沿着 db_roll_ptr 找上一个版本,重复判断。
4. 两种读操作
| 读类型 | 说明 | 实现方式 |
|---|---|---|
| 快照读(snapshot read) | 不加锁,读取历史版本 | 基于 mvcc + read view |
| 当前读(current read) | 读取最新版本,需要加锁 | select ... for update/ dml 语句 |
只有普通
select是快照读,其他操作(update、delete等)都是当前读,需要加锁
5. 与事务隔离级别的关系
| 隔离级别 | mvcc 行为 |
|---|---|
read uncommited | 不适用 mvcc,直接读最新版本(可能脏读) |
read commited | 每次select都生成新的read view,能看到其他事务已提交的最新修改 |
repeatable read | 事务开始时生成一个read view,整个事务复用,保证可重复读 |
serializable | 不使用 mvcc,所有操作加锁 |
mysql 默认隔离级别为
repeatable read
附:rc、rr级别下的innodb快照读有什么不同:
1、首先mysql四种隔离级别:
1)未提交读(read uncommited)脏读
2) 已提交读 (read commited)简称(rc) 不可重复读
3)可重复读(repeatable read)简称(rr )
4)可串行化(serializable)
2、因为read view生成时机的不同,从而造成rc、rr级别下快照读的结果的不同:
1)、在rr级别下的某个事务的对某条记录的第一次快照读会创建一个快照即read view将当前系统活跃的其他事务记录起来,此后调用快照读的时候,还是使用的是同一个read view, 所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用都是同一个read view,所以对之后的修改不可见。
2)、在rr级别下,快照读生成readview时,read view会记录此时所有其他活跃事务的快照,这些事务的修改对于当前事务都不可见的, 而早于read view创建的事务所做的修改均是可见。
3)、在rc级别下,事务中,每次快照读都会新生成一个快照和read view,这就是我们在rc级别下的事务中可以看到别的事务提交的更新的原因。
总结
到此这篇关于mysql多版本并发控制(mvcc)的文章就介绍到这了,更多相关mysql多版本并发控制内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论