MySQL中的MVCC是什么

MVCC是一种数据库并发控制机制,通过维护多个版本的数据和UndoLog记录,解决读写冲突,支持快照读,减少锁竞争。文章详细解释了MVCC的工作原理,包括事务Id、UndoLog的结构,以及读已提交和可重复读隔离级别的区别,以及它在解决幻读问题上的作用。
摘要由CSDN通过智能技术生成

什么是MVCC

  • 多版本并发控制,用于**解决读写冲突**,在一个数据行正在进行写操作时,另外的事务想要可以**读取以前版本的数据**,从而不会被阻塞,提高并发效率。
  • **快照读**不会进行阻塞,读取的是**旧版本的数据**,使用方法即**普通的查询**
  • **当前读****阻塞**直到获取到数据行的**共享锁**,读取的是**新版本的数据**
SELECT * FROM A FOR UPDATE
SELECT * FROM A LOCK IN SHARE MODE
INSERT
DELETE 
UPDATE

MVCC实现原理

在行对象中,包含**三个隐藏字段**

  1. **DB_TRX_ID** 最后一次修改数据列的事务ID
  2. **DB_ROLL_PTR** 回滚Undo Log指针链表
  3. 当没有主键时,该列作为**主键列**

image.png

旧版本数据的存储来源

**Undo Log**是先前事务操作的**逻辑逆操作**语句,在Undo Log回滚指针链表中,事务对数据行进行**修改操作**时,都会生成**Undo Log**,以**头插法**的形式插入到**回滚指针链表**中,保证新生成的UndoLog在**链表的头部**。Undo Log与行对象一样包含两个属性,**生成该Undo Log的事务Id****指向下一个Undo Log日志的指针**。因此当某个事务在进行该数据行的写操作时,其他的事务在读取该数据行时,可以根据**事务Id**和Undo Log 进行SQL语句的回滚,从而获取到以前版本的数据。因为是头插法插入,Undo Log的生成时间从新到旧。如果查询到**最后一条**Undo Log日志,事务Id还不匹配,则说明该列不能被当前事务所看到。

如何判断Undo Log是否满足条件

事务在进行读取操作时,会先获取到**Read View**,根据这里的信息来判断数据行中哪些Undo Log满足条件。

Read View中包含以下内容。
  1. 创建**当前**Read View的**事务Id**
  2. 当前活跃的**事务Id数组**,即事务为活动中状态,并且没有进行提交。
  3. 当前活跃的事务中,**Id最小的事务**
  4. **系统中下一个事务的分配值****大于**所有活跃事物Id
Read View结合Undo Log的判断方法
  1. 如果**当前Undo Log**的事务Id**小于** Read View中的最小id,则说明当前数据行的最后修改事务**已经提交**,说明该条符合条件。
  2. 如果**当前Undo Log**的事务Id**大于等于** Read View中的**下一个分配值**,则说明当前数据行的事务是在当前 Read View **生成之后才创建的**,说明该条不符合条件。
  3. 如果当前Undo Log的事务Id大于等于最小Id,并且小于事务最大Id,则需要在判断该**数据行的事务Id是否在活跃事物的列表中**,如果该数据列的事务**在活跃事务的列表**中,说明该事务**没有提交**,说明该条不符合条件,如果**不在活跃事务的列表**中,则说明该**事务已经提交**,符合条件。
  4. 如果该条数据行不符合条件,则会根据**UndoLog版本链继续向下查询**,如果在查询过程中发现符合条件的则返回,如果直至找到链表的**末尾仍不符合条件**,则说明该事务**不能**看到该条数据行。

读已提交和可重复读的区别

  1. **读已提交**隔离级别中,开启事务后**每一次**进行数据的读取都会**重新读取一次 Read View数据**。因此在其他的事务进行提交后,该事务的id会从Read View中的活跃事务Id中移除,可以读取到其他事务已提交的数据。
  2. **可重复读**隔离级别中,开启事务后**只有第一次进行数据的读取才会读取一次 Read View数据**。在其他的事务进行提交后,会有更多的Undo Log往该数据行的回滚日志中进行插入,但是Read View中的活跃事务Id表没有改变,因此不会读取到其他事务已提交的数据,保证了可重复读的特性。

MVCC如何解决幻读

  1. **可重复读**隔离级别中可以**解决部分幻读**的问题
  2. **可重复读**隔离级别中,读取数据时**只会在第一次查询时**生成Read View。
  3. 假设该事务A在第一次读取了一部分数据,此时事务B插入了一些数据,并且提交事务。
  4. 如果在事务A创建Read View时,**事务B已经开启**,则事务B处于**事务活跃的Id列表**中,此时事务A不会读取到事务B的新插入的数据。
  5. 如果在事务A创建Read View时,**事务B还未开启**,则事务B的事务Id大于事务A **Read View存储的下一个分配的最大事务Id**,此时事务A也不会读取到事务B新插入的数据
  6. MVCC**不能完全解决幻读**,在事务A通过update并且where没有条件时,**修改了事务B刚插入的记录**,此时事务A中可以读取到事务B的这条记录,并且是被事务A修改过的

MVCC总结

  1. 数据行中删除仅作为标记位,目的是为了给MVCC提供服务,要保留数据行的历史数据。
  2. MVCC解决了读写冲突的问题
  3. 因为减少了锁的使用,降低了死锁的概率
  4. 解决了快照读的问题,可以查询到之前某个时间节点的数据行快照信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值