笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》

8.a) --事务到底是隔离还是不隔离的?

  这部分内容不太容易理解,笔者也是进行了多次阅读。因此引用原文:

  之前有提到过,如果是在可重复读隔离级别,事务T启动的时候会创建一个视图read-view,之后事务T执行期间,即使有其他事务修改了数据,事务T看到的仍然跟在启动时看到的一样,也就是说,一个在可重复读隔离级别下执行的事务,好像与世无争,不受外界影响。

  但是,在之前也行锁相关内容时又提到,一个事务要更新一行,如果刚好有另外一个事务拥有这一行的行锁,它又不能这么超然了,会被锁住,进入等待状态。问题是,既然进入了等待状态,那么等到事务自己获取到行锁要更新数据的时候,它读到的值又是什么呢?

  举一个例子,下面是一个只有两行的表的初始化语句。

mysql> CREATE TABLE `t` (
  `id` ) NOT NULL,
  `k` ) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
,),(,);

    图一, 事务A, B, C的执行流程

  这里我们需要注意的是事务的启动时机。

  begin/start transaction命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用start transaction with consistent snapshot命令。

  • 第一种启动方式,一致性视图是在执行第一个快照读语句时创建的。
  • 第二种启动方式,一致性视图是在执行start transaction with consistent snapshot时创建的。

  还需要注意,没有特殊说明的情况下,我们默认autocommit=1.

  在上面这个例子中,事务C没有显示的使用begin/commit,表示这个update语句本身就是一个事务,语句完成时会自动提交。事务B在更新了行之后查询;事务A在一个只读事务中查询,并且时间顺序上是在事务B的查询之后。这时候,如果告诉你事务B查询到的K值是3,而事务A查到的k的值是1,你是不是感觉有点晕呢?

  所以今天这篇文章就是想和你说明这个问题。在MySQL里有两个视图概念:

  • 一个是view,它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是create view...,而它的查询方法与表一样。
  • 另一个是InnoDB在实现MVCC时用到的一致性视图,即consistent read view,用于支持RC(Read Commited 读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。

  它没有物理结构,作用是事务执行期间用来定义“我能看到什么数据”.

“快照”在MVCC里是怎么工作的?

  在可重复读的隔离级别下,事务在启动的时候就“拍了个快照”,注意,这个快照是基于整个数据库的。这时,你可能觉得这不太现实,毕竟如果一个库有100G,那么我启动一个事务,MySQL就要拷贝100G的数据,这个过程得多慢啊。可是平常执行事务却很快。实际上,并不需要拷贝这100G的数据。我们先来看看这个快照是怎么实现的。

  InnoDB里面每个事务有一个唯一的事务ID,叫做transaction id。它是在事务开始的时候向InnoDB的事务系统申请的,是按申请顺序严格递增的。

  而且,每行数据也是有多个版本的,每次事务更新的时候,都会生成一个新的数据版本,并且把transaction id 赋值给这个数据版本的事务ID,记为row trx_id。同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。也就是说,数据表中的每一行记录,其实可能有多个版本(row),每个版本有自己的row trx_id。

  如图2所示,就是一个记录被多个事务连续更新后的状态。

  

    图2 行状态变更图

  图中虚线框里是同一行数据的4个版本,当前最新版本是V4,k的值是22,它是被transaction id为25的事务更新的,因此它的row trx_id也是25.你可能会问,前面的文章不是说,语句更新会生成undo log(回滚日志)吗?那么,undo log在哪儿呢?实际上,图2中的三个虚线箭头,就是undo log;而V1,V2,V3并不是物理上真实存在的,而是每次需要的时候根据当前版本和undo log计算出来的。比如,需要V2的时候,就是通过V4依次执行U3,U2算出来。明白了多版本和row trx_id的概念后,我们再来想一下,InnoDB是怎么定义那个“100G”的快照的。按照可重复读的定义,一个事务启动的时候,能够看见所有已经提交的事务结果。但是之后,这个事务执行期间,其他事务的更新对它不可见。

  因此,一个事务只需要在启动的时候声明说,“以我启动的时刻为准,如果一个数据版本在我启动之前生成,就认;否则就不认。必须要找到它的上一个版本。当然,如果‘上一个版本’也不可见,那就得继续往前找”。除此之外,如果这个事务自己更新的数据,它自己还是要认的。在实现上,InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指的就是,启动了但还没提交。数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为搞水位。这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。而数据版本的可见性规则,就是基于数据的row trx_id和这个一致性视图的对比结果得到的。这个视图数组把所有的 row trx_id分成了几种不同的情况。

  

  图3, 数据版本可见性规则

  这样,对于当期事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:

  1. 如果落在绿色部分,表示这个版本是已提交的事务或者是当期事务自己生成的,这个数据是可见的。
  2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的。
  3. 如果落在黄色部分,那就包括两种情况。a. 若row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见。b.若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

  所以你现在知道了,InnoDB利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。接下来我们回顾一下图1中的三个事务,分析事务A的语句返回的结果,为什么是k=1.

  未完待续.....

MySQL 笔记整理(8.a) --事务到底是隔离还是不隔离的?的更多相关文章

  1. 最全mysql笔记整理

    mysql笔记整理 作者:python技术人 博客:https://www.cnblogs.com/lpdeboke Windows服务 -- 启动MySQL net start mysql -- 创 ...

  2. MySQL 笔记整理(8.b) --事务到底是隔离还是不隔离的?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 8.a) --事务到底是隔离还是不隔离的? 本周工作较忙,加上懒惰,拖更 ...

  3. MySQL 笔记整理(1) --基础架构,一条SQL查询语句如何执行

    最近在学习林晓斌(丁奇)老师的<MySQL实战45讲>,受益匪浅,做一些笔记整理一下,帮助学习.如果有小伙伴感兴趣的话推荐原版课程,很不错. 1) --基础架构,一条SQL查询语句如何执行 ...

  4. MySQL 笔记整理(3) --事务隔离,为什么你改了我还看不见?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 3) --事务隔离,为什么你改了我还看不见? 简单来说,事务就是要保证一组数据操作,要么全部成功,要么全部失败.在MySQL中,事务 ...

  5. MySQL 笔记整理(16) --“order by”是怎么工作的?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 16) --“order by”是怎么工作的? 在林老师的课程中,第15 ...

  6. MySQL 笔记整理(14) --count(*)这么慢,我该怎么办?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 14) --count(*)这么慢,我该怎么办? 有时你会发现,随着系统 ...

  7. MySQL 笔记整理(20) --幻读是什么,幻读有什么问题?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 20) --幻读是什么,幻读有什么问题? 我们先来看看表结构和初始化数据 ...

  8. MySQL 笔记整理(19) --为什么我只查一行的语句,也执行这么慢?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 19) --为什么我只查一行的语句,也执行这么慢? 需要说明一下,如果M ...

  9. MySQL 笔记整理(11) --怎么给字符串字段加索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 11) --怎么给字符串字段加索引? 日常工作中的登录系统,你很可能会使 ...

随机推荐

  1. 在vue中使用sass的配置的方法

    1.安装sass的依赖包 npm install --save-dev sass-loader //sass-loader依赖于node-sass npm install --save-dev nod ...

  2. BUAA_OO Summary——多项式求导问题

    从C.DS.计组一路折磨过来, 几乎都在采用过程化.函数式的编程思想.初接触面向对象的项目开发,经过了三周的对多项式求导问题的迭代开发,经历了设计.coding.测评环节,算是对面向对象有了一定的认识 ...

  3. python获取函数注释 __doc__

    使用 help  函数 可以查看 函数的注释内容 但是它也有点"添油加醋" 其实函数的注释被保存在 __doc__属性里面  PS 双下划线 def f(): "&quo ...

  4. vue本地项目设置通过手机访问

    最近再用vue写一个移动端的应用,想通过手机访问看看页面效果,于是有了下文. 1.shif+右键打开命令行工具,输入ipconfig,回车,得到电脑的ip 2.找到工作目录下的config文件夹中的i ...

  5. Vue 单文件原件 — vCheckBox

    简书原文 做东西一向奉行的是致简原则,一定要让使用者简单 这是我在使用 Vue 一段时间后尝试制作的一个小玩意 我希望可以做一堆这样的小玩意,随意组合使用,感觉挺好的 源码在最后 演示DEMO 示例: ...

  6. Senparc.Weixin.MP SDK 微信公众平台开发教程(二十):使用菜单消息功能

    在<Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明>教程中,我们介绍了如何使用“客服接口”,即在服务器后台,在任意时间向微信发送文本.图文.图片等不 ...

  7. 【安富莱二代示波器教程】第16章 附件A---电阻屏触摸校准

    第16章      附件A---电阻屏触摸校准 二代示波器的触摸校准比较简单,随时随地都可以做触摸校准,按下K1按键即可校准.有时候我们做触摸校准界面,需要在特定的界面才可以进入触摸校准状态,非常繁琐 ...

  8. 吴恩达机器学习笔记55-异常检测算法的特征选择(Choosing What Features to Use of Anomaly Detection)

    对于异常检测算法,使用特征是至关重要的,下面谈谈如何选择特征: 异常检测假设特征符合高斯分布,如果数据的分布不是高斯分布,异常检测算法也能够工作,但是最好还是将数据转换成高斯分布,例如使用对数函数:

  9. JDK设计模式之——装饰者模式

    假定已经有三个类A,B和C他们的继承关系如下          ClassA Class B extends A  Class C extends A  想进一步扩展类B和类C的功能,新增三个方法 m ...

  10. [Swift]LeetCode346. 从数据流中移动平均值 $ Moving Average from Data Stream

    Given a stream of integers and a window size, calculate the moving average of all integers in the sl ...