MVCC详细介绍及面试题

目录

1.什么是mvcc?

2.问题引入

3. MVCC实现原理?

3.1 隐藏字段

3.2 undo log 日志

3.2.1 undo log版本链

3.3 readview

3.3.1 当前读

​编辑

3.3.2 快照读

3.3.3 ReadView中4个核心字段

3.3.4 版本数据链访问的规则(了解)

4.面试题



前言:mysql中的Redolog日志保证了事务的持久性,Undolog保证了事务的原子性和一致性(回滚)

那事务的隔离性是怎么保证的呢?

答:

1. 锁:排他锁(如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁)

2. mvcc:多版本并发控制

这里主要讲一下mvcc

1.什么是mvcc?

多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突

2.问题引入

下面是一行数据,事务2、3、4都并发的对这行数据进行修改,而事务5要查询两次这行的最新数据,问查询到的是哪一次事务执行到的结果?

如果你看到这里不知道结果,请你继续往下看

3. MVCC实现原理?

MVCC的具体实现,主要依赖于数据库记录中的隐式字段undo log日志readView。      

3.1 隐藏字段

3.2 undo log 日志

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。

而update、delete的时候,产生的undo log日志不仅在回滚时需要,mvcc版本访问也需要,不会立即被删除。

3.2.1 undo log版本链

不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。

下面是事务

3.3 readview

ReadView(读视图)是快照读。是一个事务在执行 快照读(SELECT 等语句) 时生成的,它保存了4个关键字段(3.4.3 有介绍)

3.3.1 当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,

如:select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读。

3.3.2 快照读

简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

读已提交 RC (Read Committed:每次select,都生成一个快照读。

可重复读 RR (Repeatable Read)(MySQL 的默认隔离级别):开启事务后第一个select语句才是快照读的地方。

3.3.3 ReadView中4个核心字段

ReadView(读取视图) 是一个事务在执行 快照读(SELECT 等语句) 时生成的,它保存了以下关键字段:

还以下面的例子来解释:

事务五第一次查询id为30的记录,此时:

m_ids:当前活跃的事务ID集合是事务三、四、五。因为在事务五第一次查询之前事务二已经提交了(事务执行完毕)。

min_trx_id:最小活跃事务ID是事务三的id为3

max_trx_id:预分配事务ID,当前最大事务ID+1(因为事务ID是自增的),为事务5的id+1是6 

creator_trx_id:ReadView创建者的事务ID ,即为是事务五的id 5

不同的隔离级别,生成ReadView的时机不同:

读已提交 RC READ COMMITTED :在事务中每一次执行快照读时生成ReadView。

可重复读 RRREPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

3.3.4 版本数据链访问的规则(了解)

①. trx_id  == creator_trx_id ? 可以访问该版本

②. trx_id < min_trx_id ? 可以访问该版本

③. trx_id > max_trx_id ?  不可以访问该版本

④. min_trx_id <= trx_id <= max_trx_id ?  如果trx_id不在m_ids中是可以访问该版本的

还以下面5个事务来举例子:

还以事务五第一次查询举例分析可以得到以下结论

上述 ①~④ 是 InnoDB 在使用 MVCC 机制进行快照读(Snapshot Read)时判断一个版本是否可见的规则,目的是为了实现事务隔离性(尤其是可重复读)

核心依据是将数据行上的 trx_id 与当前事务的 ReadView(读取视图)中的一些字段做比较,判断是否可以“看到”这个版本。

详细解释:
①.当前事务的id(未知),等于事务创建者的id(这里是事务五),所以当前事务是事务五,说明当前数据是由“我自己”这个事务修改的。MVCC 当然允许自己看到自己改过的数据(包括未提交的),以确保 读到的是自己操作后的最新快照

②.当前事务的id(未知),小于最小活跃事务ID(这里是事务三),所以当前事务是事务二,而事务二已经提交,

  • 说明这个事务在我生成 ReadView 之前就已经提交了。

  • 因此是 对我“可见”的历史版本数据

③.当前事务的id(未知),大于最大活跃事务ID+1(这里是事务五),所以当前事务是事务六,事务六在此时ReadView 生成时,事务六还没有创建

  • 所以它对我来说是“未来”的数据。

  • 根据事务隔离的原则,我不能看见这个数据版本。

④. min_trx_id <= trx_id <= max_trx_id,这个事务是在我生成 ReadView 时是活跃的(ID 在 min~max 之间),但它不在活跃事务列表 m_ids,说明它已经 提交完成了,因此我可以看见它。和②.表达的意思一样

不同的隔离级别,生成ReadView的时机不同:

读已提交 RC READ COMMITTED :在事务中每一次执行快照读时生成ReadView。

可重复读 RRREPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

举例:

4.面试题

### MySQL MVCC 面试题及答案 #### 什么是多版本并发控制 (MVCC),其主要优点是什么? MVCC 是一种用于数据库管理系统的技术,允许多个事务同时访问同一数据的不同版本而不互相干扰。最大的好处在于读操作不需要加锁,读写之间也不会发生冲突,这大大提高了 MySQL 数据库系统的并发性能[^1]。 #### InnoDB 中如何实现 MVCC 来保证事务的隔离性? InnoDB 使用隐藏列 `DB_TRX_ID` 记录最近更新这条记录的事物 ID 和 `DB_ROLL_PTR` 指向回滚段的位置。每次修改数据时,旧的数据会被保存到 undo 日志中形成一个链表结构。当有新的查询请求到来时,系统会根据当前事物的状态创建 ReadView 并沿着版本链寻找符合条件的第一个版本返回给用户[^5]。 #### 不同隔离级别下 MVCC 表现有何差异? - **读未提交(READ UNCOMMITTED)**: 这种情况下实际上并没有真正利用上 MVCC 特性,因为可以看到其他尚未提交事务所做的更改。 - **读已提交(READ COMMITTED)**: 每次执行 SELECT 查询都会重新计算一个新的 ReadView ,这意味着即使在同一事务内也可能看到不同的结果集[^3]。 - **可重复读(REPEATABLE READ)**: 整个交易期间只会有一个固定的 ReadView 。因此,在同一个事务内的多次相同条件下的 select 操作总是能看到一致的结果集合。 - **串行化(SERIALIZABLE)**: 此模式强制所有的读取都采用共享锁的方式来进行,从而完全避免了幻影读现象的发生。 #### 解析一条 SQL 执行过程中涉及哪些组件以及它们之间的交互流程? 对于每条进入 MySQL Server 的 SQL 请求而言: 1. 客户端通过连接器与服务器建立 TCP/IP 或者 Unix Socket 形式的网络链接; 2. 如果启用了 Query Cache 功能,则在此处检查是否有匹配项可以直接返回; 3. 经过解析器完成词法和语法层面的校验之后生成抽象语法树 AST; 4. 接下来由预处理模块做更深层次的安全性和合法性检测; 5. 优化器依据多种因素评估不同可能路径的成本开销并挑选最优方案作为最终决定; 6. 最终交由执行器按照既定策略调用底层存储引擎 API 获取所需资源直至全部结束为止; 7. 结果逐步反馈至前端应用层面上显示出来的同时也会被缓存起来供后续重用[^4]。 ```sql SELECT * FROM orders WHERE order_date >= '2023-01-01'; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值