简单图文版MVCC讲解

在讲MVCC之前,当然得知道MVCC解决了什么问题,MVCC(Multi-Version Concurrency Control:多版本并发控制)主要解决的是多个事务并发引起的问题

关于数据库的多事务并发问题,这就是老生常谈的问题了,我这里稍微带一下:

  • 脏写:事务B修改了事务A改过的值,此时事务A未提交,如果事务A最终回滚的话,那么事务B修改的值也就没了
  • 脏读:事务B查询了事务A修改过的数据,但是此时事务A还没提交,如果事务A回滚事务的话就会造成事务B再次查询就读不到刚才事务A修改的数据了
  • 不可重复读:事务A查询一条数据,事务B修改了这条数据并提交事务,此时事务A再次查询的时候发现数据就不一样了
  • 幻读:事务A查询了很多条数据,事务B增删了这些数据,事务A再查询的时候,发现查询出来的数据不一样了

其中不可重复读和幻读看起来很相似,他们的区别是,不可重复读主要针对的是update操作,而幻读针对的是insert和delete操作

那么为了解决上面说的四个问题,就有了SQL标准(非MySQL)中规定的四种事务隔离级别

  • read uncommitted(读未提交) :解决脏写
  • read committed(读已提交) :解决脏读
  • repeatable read(可重复读):解决不可重复读
  • serializable(串行化):解决幻读

MySQL中的RR(repeatable read)级别就可以解决上面所说的四种问题,这里面依靠的就是MVCC,不过在这之前,还有一个概念,就是undo log版本链(undo log我之前的博客中有写过,点这里

其实每条数据都有两个隐藏字段,一个是trx_id,代表最近最近一次更新这条数据的事务id,另一个字段是roll_pointer,这个字段指向了这个实际undo log的回滚日志

举个例子,假如有一个事务A(事务id为1)插入了一条数据,此时就会生成一条undo log,但是他的roll_pointer不会指向任何undo log,因为这是第一条数据,接下来有一个事务B(事务id为2),修改了这条数据,就会生成一条新的undo log,然后这个undo log的roll_pointer就会指向事务A生成的那条undo log,接着又有一个事务C(事务id为3)也修改了这条数据,会跟事务B做一样的事情,事务C的undo log的roll_pointer会指向事务B的undo log,这样就形成了一条undo log版本链,如下图所示
undo log版本链
现在我们已经了解了undo log版本链,有了这个基础之后,就可以使用undo log版本链来实现ReadView机制,ReadView机制主要包含四个东西:

  • m_ids:此时有哪些事务在MySQL中执行还没提交
  • min_trx_id:m_ids里最小的值
  • max_trx_id:MySQL下一个要生成的事务id,就是最大事务id
  • creator_trx_id:当前你这个事务的id

扯了这么多,那么MVCC和ReadView机制又有什么关联呢?之前我们讲过了MySQL的RR隔离级别就可以解决脏写、脏读、不可重复读、幻读这几个问题,那么是如何实现的呢?

其实MVCC就是依赖ReadView机制来解决多事务并发处理问题的,下面举个例子来说:

我们假设有两个事务A(事务id为2)、B(事务id为3)并发执行,现在数据库已经由事务id为1的事务生成了一条数据(值为10),事务A发起一个查询请求,此时生成了一个ReadView,如图所示
1
那么此时事务A能否看到这条数据呢?答案是可以的,因为在ReadView中的min_trx_id是2,比undo log版本链中的trx_id要大,这说明了此时数据库中的数据是在事务2执行之前就生成了的

现在假设并发并发执行的事务B执行了一条update操作,那么按照我们上面说的undo log版本链机制,此时会新生成一条undo log,指向trx_id为1的这条undo log
2
现在我们假设事务A再次进行查询,会查询到事务B修改的值吗?答案是不会,这里的关键点在于事务A的ReadView一旦生成,就不会再改变了,所以我们再来看事务A的ReadView,里面的m_ids包含了2和3,说明事务A和事务B是同时运行的,而且事务B修改形成的undo log中的trx_id为3,所以此时事务A就会顺着版本链往下找到trx_id为1的这条数据,也就是不在并发事务中的这条数据

接下来我们假设另外一个场景,事务A使用的是范围查询,只要值大于等于10都会被查出,事务A和事务B还是按照上面的场景运行,接下来有一个事务C(事务id为4),往数据里面添加了一条数据,如下图所示
3
那么此时事务A在执行一次查询的话,能查询到事务C增加的这条数据吗?答案是不能,因为事务C的事务id大于等于了事务A生成的ReadView中的max_trx_id,这就说明事务C是在事务A执行之后才执行的,所以事务A是不能查询到事务C的执行结果的,只能顺着undo log版本链继续往下寻找

通过undo log版本链和ReadView机制,就能实现MVCC,从而解决事务并发执行造成的各种问题

MVCC(Multi-Version Concurrency Control)是一种并发控制技术,主要用于数据库管理系统中处理并发事务的冲突。MVCC允许事务在读取数据时不会被其他事务修改,从而实现了更高的并发性和隔离级别。 在MVCC中,每个事务操作的数据都有多个本。当一个事务开始时,它会创建一个事务开始时间戳,并且只能看到在该时间戳之前提交的数据本。而其他事务对同一数据进行修改时,会创建新的数据本,并将其与修改事务的开始时间戳关联。 基于MVCC的并发控制可以通过以下方式实现: 1. 读操作:在读取数据时,事务只能看到早于其开始时间戳的已提交本。这样可以避免脏读和不可重复读的问题。 2. 写操作:当一个事务进行写操作时,会创建一个新的数据本,并将其与该事务的开始时间戳关联。其他事务在该事务提交之前只能看到旧本的数据。 3. 事务隔离级别:MVCC可以支持不同的事务隔离级别,如读未提交、读已提交、可重复读和串行化。这些隔离级别可以根据应用程序的需求进行配置。 MVCC的优点是能够提供更高的并发性和隔离级别,减少了锁的冲突和等待时间。然而,它也会增加存储空间的开销,因为每个数据本都需要保存。此外,MVCC可能导致长事务持有过多的旧本数据,增加了垃圾回收的复杂性。 总的来说,MVCC是一种强大的并发控制技术,可以提高并发性和隔离级别,但需要权衡存储空间和垃圾回收的开销。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值