MySQL事务之MVCC------------------------个人总结

前言

看了从根本上理解MySQL之后,对MVCC有了一定的了解,因此决定写一篇博客来记录一下。本文会从事务隔离级别到版本链到MVCC循序渐进,可以根据自己情况目录快进。

事务的隔离级别

在了解事务的隔离级别之前,要先知道并发事务会发生的问题。至于为什么会出现并发问题,因为事务在执行的时候并不是串行执行的,不是执行完一个事务在执行另一个事务。

  • 脏写。事务A修改了另一个事务B未提交的记录,即使A提交了事务,如果B回滚的话,事务A提交的事务将不复存在。这是非常严重的问题,在各种隔离级别下都不允许存在。
  • 脏读。事务A读取事务B修改了但没有提交的值,如果事务B回滚,那么A读到的就是脏数据。
  • 不可重复读。如果要连续读10次记录A,并且需要读入的结果是相同的,但是读入过程中,如果其他事务修改了记录A的值,如果不做任何处理,那么会导致读入最新的值。
  • 幻读。如果事务A根据一些条件查询出来一些记录,然后事务B插入了一些记录,这样会导致A再次根据相同的条件查询的时候,查询到一些之前没有的记录,就和出现了幻觉一样。

另外,值得一提的是,如果事务B删除了原本的一些记录,导致A同样的条件查询出来的记录少了一些,这样算幻读吗?
这个应该算作不可重复读。幻读强调的是读取到之前没有的记录

根据对这些问题的严重性,设置了一些隔离级别来解决这些问题。(当然,这个是舍弃了一部分的隔离性来换取的性能)

  • READ UNCOMMITTED:未提交读。
  • READ COMMITTED:已提交读。
  • REPEATABLE READ:可重复读。
  • SERIALIZABLE:可串⾏化。
    在这里插入图片描述
    需要注意的是,在MySQL中,可重复读是MySQL默认的隔离级别,并且解决了幻读的问题

版本链

每次对记录进行改动的时候(比如更新),都会生成一个undo日志,undo日志有一个trx_id(事务id)和roll_pointer(指向下一个undo日志的指针),按照trx_id形成一个双向链表。

  • 进行事务操作
    在这里插入图片描述
  • 形成的版本链
    在这里插入图片描述
    这样看起来,所谓版本链就是各个事务操作的版本记录,以链表串起来。
    这样,如果是读取未提交的隔离模式,直接读取版本链的最新节点就可以了。那如果是读取已提交和读取未提交怎么办呢?那就看底下的MVCC内容吧

MVCC

读取已提交的模式下,需要关心的问题就是读取记录的时候要去用版本链的那一个版本的记录?读取已提交需要读取事务已经提交的记录,需要判断那个版本是可见的。这个时候,提出了一个概念叫做ReadView。总的来说,ReadView就是用来判断哪个版本的记录是可见的。

ReadView有四个重要的内容:

  • m_ids:表示在⽣成ReadView时当前系统中活跃的读写事务的事务id列表
  • min_trx_id:表示在⽣成ReadView时当前系统中活跃的读写事务中最⼩的事务id,也就是m_ids中的最⼩值。
  • max_trx_id:表示⽣成ReadView时系统中应该分配给下⼀个事务的id值。(并不是最大的事务id哦,是下一个)
  • creator_trx_id:表示⽣成该ReadView的事务的事务id。

如果在读取已提交的隔离模式下
在每次读取数据的时候,都生成一个ReadView,这个时候记录活跃的事务列表,最小的事务id,下个事务id,ReadView本身的事务id。接下来去版本链里面找到合适的版本。

版本链的版本记录有一个事务trx_id,用trx_id和ReadView里面的四个属性比较,就可以找到合适的版本记录了

  1. trx_id == creator_trx_id。 说明是当前事务访问的是自己修改过的记录,可以直接访问,这个版本的记录可见
  2. trx_id < min_trx_id。 表明这个版本记录已经被提交过了,执行这个版本记录的事务在生成ReadView的时候已经不是活跃的。这个版本可见,不继续往下找了
  3. trx_id > max_trx_id。这个版本记录的事务还没有被提交,不可见,看下一个版本记录是否可见
  4. min_trx_id < trx_id < max_trx_id.。 这个时候要去判断一下,去m_ids列表里面看看这是id的事务是不是活跃的,如果是活跃的表示还没有提交,不可见,继续找下一个版本记录判断

就此,读取已提交的读取流程就已经判断完了。其实可重复读和读取已提交的流程差不多。
只是读取已提交是一个事务中,每次读取(select)都要生成一个ReadView;而可重复读,只会在事务的第一次读取生成一个ReadView,找到可见的版本记录,这样后面重复读取都会读到同一个记录。

具体的可见从根本上理解MySQL(下)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值