MySQL InnoDB 事务隔离级别的实现原理

云惠网小编 2021年6月17日09:32:04
评论
2109字阅读7分1秒
摘要

今天介绍下,在 MySQL 的 InnoDB 存储引擎中,事务隔离是如何实现的。
InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。
对于数据库的每行记录,都会有三个隐藏字段:db_trx_id (事务 id)、db_roll_pt (回滚指针)、delete_flag(删除标记)。— 有懂的朋友,还望别细纠,其实 delete_flag 是在头信息中,这里是为了方便理解
对于 DML 操作来说:

INSERT:创建一条数据,db_trx_id 的值为当前事务 id, db_roll_pt 为 null 。

UPDATE:复制一行数据,将当前复制后这一行的 db_trx_id 置为当前事务的 id,db_roll_pt 是一个指针,指向复制前的那一条的。

DELETE:复制一行数据,将当前复制后这一行的 db_trx_id 置为当前事务的 id,db_roll_pt 是一个指针,指向复制前的那一条的。并把 delete_flag 置为 true 。

阅读全文 »

广告也精彩

今天介绍下,在 MySQLInnoDB 存储引擎中,事务隔离是如何实现的。

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

对于数据库的每行记录,都会有三个隐藏字段:db_trx_id (事务 id)db_roll_pt (回滚指针)delete_flag(删除标记)。— 有懂的朋友,还望别细纠,其实 delete_flag 是在头信息中,这里是为了方便理解

对于 DML 操作来说:

  • INSERT:创建一条数据,db_trx_id 的值为当前事务 id, db_roll_ptnull
  • UPDATE:复制一行数据,将当前复制后这一行的 db_trx_id 置为当前事务的 iddb_roll_pt 是一个指针,指向复制前的那一条的。
  • DELETE:复制一行数据,将当前复制后这一行的 db_trx_id 置为当前事务的 iddb_roll_pt 是一个指针,指向复制前的那一条的。并把 delete_flag 置为 true

我们会用此语句建表及初始化数据,用于下面举例:

1
2
3
4
5
6
7
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);

数据初始状态为:

Repeatable Read 可重复读

如当前的隔离界别为 Repeatable Read ,下面是 SQL 的执行过程:

那么对于第 8,10,12,13 行来说,查询的结果应该是什么呢?

结果应该分别是:2,1,3,1 。

下面我们来逐步回放,MySQL 底层是如何实现这整个过程的:

  • 第 1 行:表示每个事务的 ID 号,其中 read view 取的是所有当前活跃的事务 ID 数组,活跃指的是,已开启并生成事务 ID 但未提交的事务。max id 取的是,目前为止,最大的事务 ID,不论是否已提交。我们还称 read view 数组中,最小的值为 min id
  • 第 2 - 4 行:表示分别开启使用,并创建此事务的 read viewmax id,要注意的是,这里我并没有使用 begin/start transaction 来开启事务,是因为它们并不会马上创建 read viewmax id,而是在执行第一条 select 语句后,来进行创建的。
  • 第 5 行为修改 k 的值,自增 1,按照上面所说的规则,修改后:

  • 第 6 行,提交 ID 为 102 的事务。

  • 第 7 行执行了一个简单查询,未手动开启事务,但也会自动开启并生成 read viewmax id,分别为 read-view: [100, 101]max-id: 103

此时会根据查询规则,进行查找,规则如下:

  1. 如果数据的 db_trx_id < min id ,则说明数据在开启当前事务前已提交的,内容可见。

  2. 如果数据的 db_trx_id > max id ,则说明数据在此事务启动后生成的,内容不可见。

  3. 如果数据的 min id <= db_trx_id <= max id ,则还分为两种情况:

    3.1 若 db_trx_idread 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 Committed 读已提交 也可套用上面的规则,不过一致性视图: read viewmax id 的创建时机,是每一条 select 语句时重新生成。你根据上面的内容,可以自己动手试验下读已提交。

腾讯云618
云惠网小编
MySQL 索引 java

MySQL 索引

索引 数据库的索引是一个要点, 无论是面试还是在工作中, 这个知识点都很常会用到, 你可能只是用过索引, 知道加了索引可以提高查询的性能, 但不知道为什么这样, 今天我们一起来详细...
MySQL 查询缓存 java

MySQL 查询缓存

MySQL 拿到一个查询请求后,会先看看之前有没有执行过这条语句,如果执行过,则直接从查询缓存中取之前查询的结果即可,但大多情况不建议使用 MySQL 的查询缓存,因为弊大于利。 ...
初识 redo log 和 binlog java

初识 redo log 和 binlog

redo log InnoDB 存储引擎是以页为单位来管理存储空间的, 我们的增删改查操作本质上都是在访问页面, 如读取一条数据, 会把这个数据所在的页加载到内存中, 而不仅仅是这...
MySQL 连接 java

MySQL 连接

进行连接 使用数据库的第一步是连接,连接命令为: 1 mysql -u$username -h$host -P$port -p 然后输入密码就行了,不推荐在 -p 的后面输入密码,...
腾讯云618

发表评论