最全解读MVCC

简介

MVCC(Multi-Version Concurrency Control)即多版本并发控制,主要是为了提高数据库的并发性能

同一行数据平时发生读写请求时,会被上锁阻塞住,但mvcc用更好的方式去处理读写请求,使其不用加锁。

这个读时快照读,而不是当前读,当前读是一种加锁操作,即悲观锁。

快照读、当前读

当前读

他读取的数据库记录,都是当前最新的版本,会对当前读取得数据进行加锁,防止其他食物修改数据。是悲观锁的一种操作。如update、insert、delete

快照读

快照读的实现是基于多版本并发控制,即MVCC,所以他读到的数据可能不是最新数据,可能是之前的数据。如不加锁的select操作

快照读和mvcc的关系

mvcc是“维持一个数据的多个版本,使读写操作没有冲突“的一个抽象概念

mvcc的实现需要快照读。

数据库的并发场景

读-读:不存在问题,不需要并发控制

读-写:有线程安全问题,可能会造成事务隔离性问题,脏读、不可重复读、幻读

写-写:有线程安全问题,可能存在更新丢失问题

MVCC解决并发问题

用来解决读-写冲突的无锁并发控制,为事务分配单项增长和时间戳。为每个数据修改保存一个版本,版本与事务时间戳相关联。

读操作只读取该事务开始前的数据库快照

  1. 并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不阻塞读操作
  2. 解决脏读、不可重复读、幻读等事务隔离性问题
  3. 不能解决写-写更新丢失问题

解决方案

MVCC+悲观锁:MVCC解决读写冲突,悲观锁解决写写冲突

MVCC+乐观锁:MVCC解决读写冲突,乐观锁解决写写冲突

MVCC实现原理

由版本链、undo日志、ReadView实现

版本链

在数据库中的每行数据,除了肉眼可见的数据,还有几个隐藏字段:db_trx_iddb_roll_pointerdb_row_id

  • db_trx_id:事务ID(自增):记录创建这条记录/最后一次修改该记录的事务ID
  • db_roll_pointer:回滚指针:指向这条记录的上一个版本
  • db_row_id:隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以db_row_id产生一个聚簇索引。
  • 实际还有一个删除flag的隐藏字段,记录被更新或删除并不代表真的删除,而实删除flag变了

 

 每次对数据库记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer,然后可以将这些日志串成一个链表。

ReadView

事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照。

记录并维护系统当前活跃事务的ID(没有commit,当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以越新的事务,ID值越大),是系统中当前不应该被本事务看到的其他事务id列表。

Read View主要是用来做可见性判断的, 即当我们某个事务执行快照读的时候,对该记录创建一个Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log里面的某个版本的数据。

属性

  • m_ids: 当前系统活跃(未提交)事务版本号集合。
  • max_trx_id: 当前read view 时“当前系统最大事务版本号+1”,即下次要分配的事务id
  • min_trx_id: 当前read view 时“系统正处于活跃事务最小版本号”
  • creator_trx_id: 创建当前read view的事务版本号;

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中是不可以访问这个版本的,反之可以

MVCC和事务隔离级别

上面所讲的Read View用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。

RC、RR生成时机

  1. RC隔离级别下,是每个快照读(select)都会生成并获取最新的ReadView;即一个事务中的每个select都会获得一个新的视图(ReadView),所以会造成不可重复读
  2. 而在RR隔离级别下,则是同一个事务中的第一个快照读(即select)才会创建ReadView, 之后的快照读获取的都是同一个视图ReadView,之后的查询就不会重复生成了,所以一个事务的查询结果每次都是一样的,这样就解决了不可重复读的问题

解决幻读问题

快照读:通过MVCC来进行控制的,不用加锁。按照MVCC中规定的“语法”进行增删改查等操作,以避免幻读。

当前读:通过next-key锁(行锁+间隙锁)来解决问题的。

RC、RR级别下的InnoDB快照读区别

在RC级别下的,事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因

在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及Read View, 将当前系统活跃的其他事务记录起来,此后在调用快照读的时候,还是使用的是同一个ReadView,所以只要当前事务在其他事务提交更新之前使用过快照读,那么之后的快照读使用的都是同一个ReadView,所以对之后的修改不可见;

即RR级别下,快照读生成Read View时,Read View会记录此时所有其他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于Read View创建的事务所做的修改均是可见
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过街的老鼠

感谢你对诗仙女的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值