前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL MVCC(多版本控制)

MySQL MVCC(多版本控制)

作者头像
shysh95
发布2022-02-16 21:29:33
1.1K0
发布2022-02-16 21:29:33
举报
文章被收录于专栏:shysh95shysh95

事务的启动时间是啥时候?

  • begin/start transaction命令不是一个事务的起点,而是在执行到第一个操作InnoDB表的语句时,事务才真正启动。
  • 如果想马上启动一个事务,可以执行start transaction with consistent snapshot命令

什么是一致性读视图?

一致性读视图是InnoDB在实现MVCC用到的视图,用于读提交(RC)和可重复度(RR)隔离级别的实现。

一致性视图没有物理结构,主要是在事务执行期间用来定义该事物可以看到什么数据。

什么是row trx_id?

事务在正式启动的时候我们会创建一致性视图,该一致性视图是基于整个库的。该一致性视图不会拷贝整个数据库的数据(因为拷贝数据是不现实的)。

InnodDB的每个事务都有一个唯一的事务ID,叫做transaction id,该ID在事务开始的时候向InnoDB申请,并且按照申请顺序严格递增。

每行数据都会有多个版本,每次事务更新数据的时候都会生成一个新的数据版本,并且把transaction id赋值给这个数据版本的事务id,称为row trx_id。

如上图所示,是一行记录被多个事务更新后的状态,该行记录的最新版本是有由transaction id为25的事务更新的,因此row trx_id也为25。

U3、U2、U1代表的是undo log,V1、V2、V3在物理上并不真实存在,而是在需要的时候通过V4配合undo log计算获得。

如何构建一致性读视图?

InnoDB会为每个事务构造一个数组,该数组用来保存事务启动瞬间当前正在活跃(启动还未提交)的所有事务ID。

数组里面事务ID的最小值为低水位,当前系统里面已经创建过的事务ID的最大值加1位高水位。该视图数组和高水位就组成了当前事务的一致性视图。

对于当前事务的启动瞬间,一个数据版本的row trx_id会有以下几种可能:

  • 如果在绿色部分,表示该版本是已提交的事务或者是自己生成的,数据可见
  • 如果落在红色部分,表示该版本是由未来的事务生成的,数据不可见
  • 如果落在黄色部分,如果row trx_id在数组中,表示该版本是由还没提交的事务生成,数据不可见;如果row trx_id不在数组中,表示该版本是已经提交了的事务生成的,可见。

上述是代码逻辑的,我们可以简化一下,一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以为,有以下几种情况:

  1. 版本未提交,不可见
  2. 版本已提交,但是是在视图创建以后提交的,不可见
  3. 版本已提交,而且是在视图创建以前提交的,可见

update逻辑和select逻辑的不同

假设id=1的k初始值为1,隔离级别为可重复读,大家可以试着分析以上三个事务的结果:

  • 事务A:k为1
  • 事务B:k为3
  • 事务C:k为2

根据我们上面将的多版本控制和一致性视图,事务A很容易得出1,事务C很容易得出2,但是如果按照上述分析,事务B的结果会和预想的不太一致,这是因为事务B中出现了update这行记录,update和单纯的select将会有些许不同。

update在更新数据时候不能在历史版本上进行更新的,也就是说事务B是在k=2的基础上进行更新,此时就需要用到一条规则:更新数据都是先读后写,并且这个读为当前读。

除了update语句以为,select如果加锁也是当前读,如下:

代码语言:javascript
复制
-- 加读锁
select k from t where id = 1 lock in share mode;
-- 加写锁
select k from t where id = 1 for update;

我们对之前的事务C做些改造,如上图,改造完成以后会发生如下情况:

  • 事务C还没提交,因此在(1,2)这个版本上的写锁还没有释放
  • 事务B又因为是当前读,必须读最新版本,而且必须加锁,因此就阻塞等待事务C释放该锁,才能继续它的当前读

事务如何实现MVCC?

  1. 每一个事务都有一个事务ID(transaction id),该ID严格递增
  2. 事务在启动时,会找到已提交的最大事务ID即为up_limit_id
  3. 事务在更新一条语句时,比如id=1改为了id=2,会把id=1和该行之前的row trx_id写到undo log中,并且在数据页将id的值修改为2,并且把修改这条语句的transaction id记在该行行头
  4. 一个事务要查看一条数据时,必须用该事物的up_limit_id与该行的transaction id做对比,如果up_limit_id>=transaction id,该数据可见,如果up_limit_id<transaction id则需要去undo log里面去取,去undo_log查找数据的时候,也需要做对比,只有up_limit_id>transaction id才可以返回数据
  5. 当前读是先读后写,会更新事务内的up_limit_id为该事务的transaction id
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档