【MySQL】8|事务到底是隔离的还是不隔离的

2022-01-13  本文已影响0人  学而思之

一方面事务是可重复读,即整个事务期间看到的都是事务刚刚启动时候的视图;但是又因为行锁,事务在执行过程中可能需要等待别的事务更新同一行,那这个时候如果该事务也要更新,看到的还是事务刚刚创建时事务的状态吗?显然不是,这里的关键就是对于更新操作来说,需要当前读。

1、begin/start transaction 命令并不是一个事务的起点,在执行他们之后的第一个操作InnoDB表的语句,事务才真正启动。

2、如果要马上启动一个事务,可以使用start transaction with consistent snapshot 命令来实现。

一致性视图是在执行第一个快照读语句时创建的。

例如:

事务A 事务B
begin;
update t set k = 100 where id = 100;
update t set k = 200 where id = 200;
select * from t;
commit;

事务A的select查询能够看到事务B的更新结果。

表明事务启动的时候,一致性视图还未创建,即update会启动事务,但是不会创建一致性视图。

一致性视图是在执行 start transaction with consistent snapshot 时创建的。

例如:

事务A 事务B
start transaction with consistent snapshot;
update t set k = 100 where id = 100;
update t set k = 200 where id = 200;
select * from t;
commit;

事务A的select查询就无法看到事务B的更新结果。表明事务和一致性视图是一起创建的。

MySQL视图的概念

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

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

在可重复读隔离级别下,事务在启动的时候就“拍了个快照”。注意,这个快照是基于整库的。

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

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

也就是说,数据表中的一行记录,其实可能有多个版本(row),每个版本有自己的row trx_id。

如下图,就是一个记录被多个事务联系更新后的状态:

同一行数据4个版本

图中是同一行数据的4个版本,当前最新版本是V4,k的值是22,它是被transaction id 为 20 的事务更新的,因此它的row trx_id 也是20。

图中的虚箭头U1、U2、U3对应的是 undo log;V1、V2、V3并不是物理上真实存在的,而是每次需要的时候根据当前版本和 undo log 计算出来的。比如,需要V2版本的时候,就是通过V4 依次执行U3、U2算出来的。

按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果。但是之后,这个事务执行期间,其他事务的更新对它不可见。

如果一个数据版本是在启动之前生成的,可见;如果是在启动以后生成的,则不可见,需要按照数据版本往回找,直到可见为止。如果是自己更新的版本,则可见。

“快照”的实现

InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指的就是,启动了但还没有提交。

数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。

这个视图数组和高水位,就组成了当前事务的一致性视图(read-view),而数据版本的可见性规则,就是基于数据的 row trx_id 和 这个一致性视图的对比结果得到的。

这个视图数组把所有的row trx_id 分成了几种不同的情况。

方式一启动事务

read_view 是在第一个select语句执行时生成的,而事务是在第一个操作InnoDB表时创建的。这就存在创建一致性读视图时,事务已经创建一段时间。此时视图数组为[103,104,105,106],低水位为102,高水位为106,当前事务为105。

方式二启动事务

read_view 和 事务是同步创建的,此时当前事务即为高水位。此时视图数组为[102,103,105],低水位为102,高水位为105,当前事务为105。

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

  1. 如果为绿色部分(肯定包括低于低水位事务),表示这个版本是已经提交的事务,这个数据是可见的
  2. 如果为红色部分(高于高水位事务),表示这个版本是由将来启动的事务生成的,不可见
  3. 如果为黄色部分,表示这个版本是未提交的事务,不可见

更新逻辑

可重复读的核心是“一致性读”,“一致性读” 针对的是读取操作,可以简单理解为 select。

但是,为了保证更新事务不丢失,更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。

读提交(RC) 和 可重复读(RR)的逻辑类似,他们最主要的区别是:

小结

InnoDB的行数据有多个版本,每个数据版本有自己的row trx_id,每个事务或者语句有自己的一致性视图。普通查询语句是一致性读,一致性读会根据row trx_id 和 一致性视图确定数据版本的可见性。

上一篇 下一篇

猜你喜欢

热点阅读