今天介绍下,在 MySQL
的 InnoDB
存储引擎中,事务隔离是如何实现的。sql
InnoDB
里面每一个事务有一个惟一的事务 ID
,叫做 transaction id
。它是在事务开始的时候向 InnoDB
的事务系统申请的,是按申请顺序严格递增的。数据库
对于数据库的每行记录,都会有三个隐藏字段:db_trx_id (事务 id)
、db_roll_pt (回滚指针)
、delete_flag(删除标记)
。— 有懂的朋友,还望别细纠,其实 delete_flag
是在头信息中,这里是为了方便理解数组
对于 DML
操做来讲:ui
db_trx_id
的值为当前事务 id
, db_roll_pt
为 null
。db_trx_id
置为当前事务的 id
,db_roll_pt
是一个指针,指向复制前的那一条的。db_trx_id
置为当前事务的 id
,db_roll_pt
是一个指针,指向复制前的那一条的。并把 delete_flag
置为 true
。咱们会用此语句建表及初始化数据,用于下面举例:spa
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`k` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
insert into t(id, k) values(1, 1);
复制代码
数据初始状态为:3d
如当前的隔离界别为 Repeatable Read
,下面是 SQL 的执行过程:指针
那么对于第 8,10,12,13 行来讲,查询的结果应该是什么呢?code
结果应该分别是:2,1,3,1 。cdn
下面咱们来逐步回放,MySQL 底层是如何实现这整个过程的:blog
第 1 行:表示每一个事务的 ID 号,其中 read view
取的是全部当前活跃的事务 ID 数组,活跃指的是,已开启并生成事务 ID 但未提交的事务。max id
取的是,目前为止,最大的事务 ID,不管是否已提交。咱们还称 read view
数组中,最小的值为 min id
。
第 2 - 4 行:表示分别开启使用,并建立此事务的 read view
及 max id
,要注意的是,这里我并无使用 begin/start transaction
来开启事务,是由于它们并不会立刻建立 read view
及 max id
,而是在执行第一条 select
语句后,来进行建立的。
第 5 行为修改 k 的值,自增 1,按照上面所说的规则,修改后:
第 6 行,提交 ID 为 102 的事务。
第 7 行执行了一个简单查询,未手动开启事务,但也会自动开启并生成 read view
及 max id
,分别为 read-view: [100, 101]
,max-id: 103
此时会根据查询规则,进行查找,规则以下:
若是数据的 db_trx_id < min id
,则说明数据在开启当前事务前已提交的,内容可见。
若是数据的 db_trx_id > max id
,则说明数据在此事务启动后生成的,内容不可见。
若是数据的 min id <= db_trx_id <= max id
,则还分为两种状况:
3.1 若 db_trx_id
在 read view
的数组中,表示这个版本是由还没提交的事务生成的,不可见,但若是是本身的事务,则可见。
3.2. 若不在数据中,则表示这个版本是已经提交了的事务生成的,可见。
示意图以下:
当前的事务的一致性视图为 read view: [100, 101]
,max id: 103
,那么根据这个规则,在上面的数据链中查询数据,从最新的蓝色,开始找,找到第一个数据的 db_trx_id
为 102,符合规则 3.2 属于可见范围,查询结果为 2。
第 8 行,当前的事务的一致性视图为 read view: [100, 101]
,max id: 101
一样根据规则,第一个数据的 db_trx_id
为 102,符合规则 2,不可见,那么根据指针 db_roll_pt
继续查找,找到 db_trx_id
为 10 的数据,符合规则 1,数据可见,查询结果为 1。
第 9 行,修改 k 的值,自增 1,按照上面所说的规则,修改后:
第 10 行,当前的事务的一致性视图为 read view: [100]
,max id: 100
一样根据规则,第一个数据的 db_trx_id
为 100,符合规则 3.1,在 read view
数组中,可是此 id 为当前事务 id,因此但是可见的,查询结果为 3。
第 11 行,当前的事务的一致性视图为 read view: [100, 101]
,max id: 101
一样根据规则,第一个数据的 db_trx_id
为 100,符合规则 3.1,在 read view
中,可是此 id 不为当前事务 id,因此内容可见的,那么根据指针 db_roll_pt
继续查找,找到 db_trx_id
为 102 的数据,符合规则 2,不可见,继续根据指针 db_roll_pt
查找,找到 db_trx_id
为 10 的数据,符合规则 1,数据可见,查询结果为 1。
第 12 - 13 行,为提交事务语句。
处于 Read Committed 读已提交
也可套用上面的规则,不过一致性视图: read view
和 max id
的建立时机,是每一条 select
语句时从新生成。你根据上面的内容,能够本身动手试验下读已提交。