笔记记录自林晓斌(丁奇)老师的《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. 纯css修改单选、复选按钮样式

    只支持IE9及以上 html <label><input class="radio" type="radio" name="radi ...

  2. 性能测试学习 第八课--LR12中针对WebServices协议的三种脚本开发模式

    一,webservices协议简介 webservices是建立可交互操作的分布式应用程序的新平台,它通过一系列的标准和协议来保证程序之间的动态连接, 其中最基本的协议包括soap,wsdl,uddi ...

  3. 适配iOS11

    总结在iOS11系统中出现的适配问题: 启动app发现上下有空隙,不能完全贴合屏幕----- 解决方案:添加一张尺寸为1125x2436的启动图. 隐藏导航栏的界面,会出现无法贴合屏幕顶部(一般来说, ...

  4. 用appuploader生成发布证书和描述性文件

    本帖最后由 长发飘 于 2017-4-13 12:34 编辑 之前用AppCan平台开发了一个应用,平台可以同时生成安卓版和苹果版,想着也把这应用上架到App Store试试,于是找同学借了个苹果开发 ...

  5. HTML5 history.pushState()和history.replaceState()新增、修改历史记录用法介绍

    抽空研究了下这两个新方法,确实可以解决很多问题 1.使用pushState()方法 可以控制浏览器自带的返回按钮: 有时候我们想让用户点击浏览器返回按钮时,不返回,或执行其他操作,这时,就用到hist ...

  6. react-native模拟机调试步骤详解 ——亲测有效!!!!

    步骤 1 下载安装夜神模拟器,去夜神官网下载即可!然后安装完成!进入到初始化项目的目录,打开cmd命令,运行adb connect 127.0.0.1:62001 链接模拟器 2 链接完成之后,运行安 ...

  7. Spring Cloud,Dubbo及HSF对比

    Round 1:背景 Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点.阿里巴巴近几年对开源社区的贡献不论在国内还是国外都是引人注目的,比如:JStorm捐赠给Apa ...

  8. [Swift]LeetCode29. 两数相除 | Divide Two Integers

    Given two integers dividend and divisor, divide two integers without using multiplication, division ...

  9. [Swift]LeetCode245.最短单词距离 III $ Shortest Word Distance III

    This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as ...

  10. [Swift]LeetCode765. 情侣牵手 | Couples Holding Hands

    N couples sit in 2N seats arranged in a row and want to hold hands. We want to know the minimum numb ...