MVCC 、CAS 和CopyOnWrite

本文探讨了多版本并发控制(MVCC)及比较并交换(CAS)机制在数据库系统中的作用与实现方式。重点讲解了MVCC如何通过为每一行数据维护版本信息来支持事务的隔离级别,以及CAS作为一种乐观锁机制如何保证数据的一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

update一行的时候的时候不是in-place的修改,而是产生一个行的新版本,在新行上修改,最后有点类似copy on write array,在提交的时候切换到新版本。好处是不影响现有数据的读取,一致性好。

概括为:准备数据 + 原子commit 切换版本,和无锁数据结构实现的思路很像,先准备好数据,最后往结构上挂的那一下用CAS原子性保证。MVCC是把一个复杂事务的原子性问题转化到commit动作的原子性上来。

CAS 是一种思想:Conditional Update,后验保证一致,而锁是前验机制。CAS的基本框架

1)读取当前状态 

2)基于读取的状态进行计算得到新状态。

3)Conditional Update:如果计算结果基于的状态没有变,则更新,否则回到第一步。


system model:

Server State A  —— Transaction  T——> Server State B

和一个版本管理系统比如TFS类比:changeset 就是 transaction, changeset number就是 transaction id

每个文件有版本,整个代码库也有版本,都是以changeset number做为版本号。整个代码库的版本历史就是所有的changeset number,是连续的,而文件的版本历史是非连续的,因为不是每个changeset都修改这个文件。


数据库

每个事务分配一个Transaction Id,是自增的。server的当前版本就是上一次成功提交的transaction Id

INNoDB实现MVCC的方法,每一行有2个隐藏字段,记录创建本行的事务ID和删除本行的事务ID(如果被删了的话)

在一个事务中:

对于insert,把当前事务ID填到新行的Create字段

对于delete,把当前事务ID填到要删除的行的Delete字段

对于update,产生一个新行,把旧行标记删除

对于select,返回的记录满足两个条件

1) 行的create事务ID 小于等于Server 当前版本号,(或者等于当前事务ID,本次事务创建的行)这确保读到的数据都是已经提交的

2)行的delete事务ID 大于当前事务ID ,当前事务之后的事务才删除的数据在当前事务可以被读到。

具体的,每个事务会拷贝一个“当前活动事务列表“,用其中最小的那个做为select的上界。相当于在事务开始的时候保存了server的版本号,之后就算有别的事务提交increment了server的版本,当前事务一直用自己保存的那个,Repeatable read。


事务提交就是更新server的当前版本为当前commit的事务号。

标记删除的数据用一个后台janitor定期处理,这个叫purge。



1

### MVCC Undo Log 的概念及其工作原理 #### 1. MVCC (多版本并发控制) MVCC 是 MySQL InnoDB 季存储引擎用来实现一致性读的一种机制,在并发场景下能够保证读取到的数据是一致的。该技术主要目的是提升数据库系统的并发性能,更好地处理读-写冲突,使得即使存在读写冲突的情况下也无需加锁即可完成非阻塞式的并发读操作[^3]。 对于普通的 `SELECT` 查询而言,默认情况下它们属于快照读的一部分,这意味着这些查询不会被其他正在修改相同数据集的事物所阻碍。相反,“当前读”,比如带有锁定提示(`LOCK IN SHARE MODE`) 或者更新/删除命令,则会遵循更加严格的协议,并可能引起等待或死锁现象发生。 #### 2. Undo Log 工作原理 Undo 日志用于保存旧版本的数据副本,当某个事务对某一行进行了更改时,InnoDB 并不会立即覆盖原有数据而是先将其状态存入 undo log 中形成一个新的节点加入到这条记录对应的版本链里。每当新版本产生时就会向前链接至之前的版本直到最初的状态为止[^4]。 具体来说: - **创建时间戳**:每行额外附加了一个表示此行何时被插入的逻辑编号; - **删除位移量**:同样地也有另一个字段指示了哪一刻起它不再有效; 以上述两个属性为基础构建起来的历史视图允许不同阶段内的事物看到各自所需的一致性图像而不互相干扰。更重要的是,通过这种方式实现了所谓的“乐观锁”策略——即假定大多数时候不会有竞争条件出现因而可以放心大胆地让多个客户端同时访问同一份资料库资源而不用担心造成破坏性后果[^5]。 ```sql -- 示例 SQL 展示如何查看特定表下的所有未提交变更 SELECT * FROM table_name WHERE db_row_id = 'specific_value' AND trx_id IS NOT NULL; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值