文章目录

  • 一、简介
  • 二、redo 日志
  • 2.1 简介
  • 2.2 工作原理
  • 2.3 刷盘策略
  • 2.4 相关参数
  • 三、undo 日志
  • 3.1 简介
  • 3.2 回滚段
  • 3.3 详细工作流程
  • 3.4 日志清理


一、简介

  • 事务四种特性的底层实现机制
  1. 事务的隔离性由 锁机制 实现。
  2. 而事务的原子性、一致性和持久性由事务的 redo 日志和 undo 日志来保证。
  3. redo log 称为 重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。
  4. undo log 称为 回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
  • redo 和 undo 都可以视为是一种 恢复操作,但 undo 并不是 redo 的逆过程
  1. redo log:是存储引擎层(innodb)生成的日志,记录的是 物理级别 上的页修改操作,比如页号xxx,偏移量yyy,写了zzz数据,主要为了保证数据的可靠性。
  2. undo log:是存储引擎(innodb)生成的日志,记录的是 逻辑操作 的日志。比如对某一行数据进行了insert语句操作,那么undo log就记录一条与之相反的delete操作。主要用于 事务的回滚(undo log 记录的是每个修改操作的 逆日志)和 一致性非锁定读(回滚行记录到某种特定版本,即多版本并发控制)。

二、redo 日志

2.1 简介

  • InnoDB 修改数据的基本流程
  1. 当我们想要修改DB上某一行数据的时候,InnoDB是把 数据从磁盘读取到内存 的缓冲池上进行修改。
  2. 这个时候数据在内存中被修改,与磁盘中相比就存在了差异,我们称这种有差异的数据为 脏页
  3. InnoDB对脏页的处理 不是每次生成脏页就将脏页刷新回磁盘,这样会产生海量的IO操作,严重影响InnoDB的处理性能。
  4. 既然脏页与磁盘中的数据存在差异,那么如果在这期间DB出现故障就会造成 数据的丢失
  5. 为了解决这个问题,redo log 就应运而生了。

2.2 工作原理

innoDB 引擎的事务采用了 WAL技术 ( write-ahead logging ),这种技术的思想就是先写日志,再写磁盘,只有日志写入成功,才算事务提交成功,这里的日志就是 redo log。当发生宕机且数据未刷到磁盘的时候,可以通过 redo log 来恢复,保证ACID 中的 D(持久性),这就是 redo 的作用。

mysql事务id查询事务日志 mysql 事务日志_回滚

  1. 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝。
  2. 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值。
  3. 当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式。
  4. 定期将内存中修改的数据刷新到磁盘中。

2.3 刷盘策略

redo log 的写入并不是直接写入磁盘的,InnoDB 引擎会在写 redo log 的时候先写 redo log buffer,之后以 一定的频率 刷入到真正的 redo log file 中。

  • innodb_flush_log_at_trx_commit

参数值

说明

0

表示每次事务提交时不进行刷盘操作。(系统默认的 master thread 每隔 1s 进行一次重做日志的同步)

1

表示每次事务提交时都将进行同步,刷盘操作( 默认值

2

表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由 os 自己决定什么时候同步到磁盘文件。

  • innodb_flush_log_at_trx_commit = 1

mysql事务id查询事务日志 mysql 事务日志_mysql_02

2.4 相关参数

  • innodb_log_buffer_size:redo log buffer 大小,默认 16M ,最大值是 4096M,最小值为 1M。
mysql> show variables like '%innodb_log_buffer_size%';
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set (0.00 sec)

mysql>
  • innodb_log_group_home_dir
  1. 指定 redo log 文件组所在的路径,默认值为 ./,表示在数据库的数据目录下。
  2. MySQL的默认数据目录( var/lib/mysql )下默认有两个名为 ib_logfile0ib_logfile1 的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。
mysql> show variables like '%innodb_log_group_home_dir%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_group_home_dir | ./    |
+---------------------------+-------+
1 row in set (0.01 sec)

mysql>
  • innodb_log_files_in_group:指明redo log file的个数,命名方式如:ib_logfile0,iblogfile1… iblogfilen。默认2个,最大100个。
mysql> show variables like '%innodb_log_files_in_group%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2     |
+---------------------------+-------+
1 row in set (0.01 sec)

mysql>
  • innodb_log_file_size
  1. 单个 redo log 文件设置大小,默认值为 48M,最大值为512G。
  2. 注意最大值指的是整个 redo log 系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size )不能大于最大值512G。
mysql> show variables like '%innodb_log_file_size%';
+----------------------+----------+
| Variable_name        | Value    |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
1 row in set (0.00 sec)

mysql>

三、undo 日志

undo log 是事务原子性的保证,在事务中 更新数据的前置操作 其实是要先写入一个 undo log。

3.1 简介

undo日志的作用:1. 回滚数据;2. MVCC

  1. 事务需要保证 原子性,也就是事务中的操作要么全部完成,要么什么也不做。
  2. 有时候事务执行到一半,可能会遇到服务器本身的错误、操作系统错误、突然断电导致的错误或者执行者手动 ROLLBACK。
  3. 以上情况出现,需要把数据改回原先的样子,这个过程称之为 回滚,这样就可以造成一个假象:这个事务看起来什么都没做,所以符合 原子性 要求。

场景

操作

插入

至少要把这条记录的主键值记下来,之后回滚的时候需要把这个主键值对应的 记录删掉

删除

至少要把这条记录的内容都记下来,这样之后回滚再把这些内容组成一条新记录 插入到表 中就好了。

更新

至少要把修改过这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。

查询

并不会修改任何用户记录,并 不需要 记录对应的undo log日志。

  1. 另外,If another transaction needs to see the original data as part of a consistent read operation, the unmodified data is retrieved from undo log records (This will be explained in more detail in the following sections MVCC).

mysql事务id查询事务日志 mysql 事务日志_mysql_03

3.2 回滚段

  • 简介
  1. InnoDB 对 undo log 的管理采用段的方式,也就是 回滚段(rollback segment)
  2. 每个回滚段记录了 1024 个 undo log segment,InnoDB 支持最大 128 个 rollback segment,故其支持同时在线的事务为 128 * 1024 个。
  3. 当开启一个事务需要写 undo log 的时候,需要先在 undo log segment 中找到一个空闲的位置再去申请 undo 页,然后在申请到的页中进行 undo log 的写入。
  • 回滚段中的数据分类
  1. 未提交的回滚数据(uncommitted undo information):该数据所关联的事务并未提交,用于实现读一致性,所以该数据不能被其它事务的数据覆盖;
  2. 已经提交但未过期的回滚数据(committed undo information):该数据关联的数据已经提交,但是仍受到 undo retention 参数的保持时间的影响;
  3. 事务已经提交并过期的数据(expired undo information):事务已经提交,而且数据保存时间已经超过 undo retention 参数指定的时间,属于已经过期的数据。当回滚段满了之后,会优先覆盖此部分数据。

事务提交后并不能马上删除 undo log 及 undo log 所在的页。这是因为可能还有其它事务需要通过 undo log 来得到行记录之前的版本;故事务提交时将 undo log 放入一个链表中,是否可以最终删除 undo log 及 undo log 所在的页由 purge 线程来判断(后续会讲到)。

3.3 详细工作流程

  • 隐藏列:对于 InnoDB 引擎来说,每个行记录除了记录本身的数据之外,还有几个隐藏的列


说明

DB_ROW_ID

如果没有为表显示的定义主键,并且表中也没有定义唯一索引,那么 InnoDB 会自动为表添加一个 row_id 的隐藏列作为主键。

DB_TRX_ID

每个事务都会分配一个事务 ID,当对某条记录发生变更时,就会将这个事务的事务 ID 写入 trx_id 中。

DB_ROLL_PTR

回滚指针,本质上就是指向 undo log 的指针。

mysql事务id查询事务日志 mysql 事务日志_数据_04

  • 执行事务
  1. INSERT:插入的数据都会生成一条 insert undo log,并且数据的回滚指针会指向它。undo log 会记录 undo log 的序号、插入主键的列和值;在进行 rollback 的时候,通过主键直接把对应的数据删除即可。
BEGIN;
INSERT INTO user (name) VALUES ("tom");

mysql事务id查询事务日志 mysql 事务日志_mysql_05

  1. UPDATE:对于更新的操作会产生 update undo log,并且会分更新主键和不更新主键
# 不更新主键时会把老的记录写入新的 undo log,让回滚指针指向新的 undo log
# 它的 undo no 会 +1,并且新的 undo log 会指向老的 undo log
UPDATE user SET name = "Sun" WHERE id = 1;

mysql事务id查询事务日志 mysql 事务日志_mysql_06

# 对于更新主键的操作,会先把原来的数据 deletemark 标识打开,这是并没有真正的删除数据,真正的删除会交给清理线程去判断
# 然后在后面插入一条新的数据,新的数据也会产生 undo log
UPDATE user SET id = 2 WHERE id = 1;

mysql事务id查询事务日志 mysql 事务日志_mysql_07

  • 回滚事务
  1. 通过 undo no = 3 的日志把 id = 2 的数据删除;
  2. 通过 undo no = 2 的日志把 id = 1 的数据的 deletemark 还原成 0;
  3. 通过 undo no = 1 的日志把 id = 1 的数据的 name 还原成 Tom;
  4. 通过 undo no = 0 的日志把 id = 1 的数据删除。

3.4 日志清理

  • undo 的类型
  1. insert undo log 是指在 insert 操作中产生的 undo log。因为 insert 操作的记录,只对事物本身可见,对其它事务不可见(事务隔离性的要求),故该 undo log 可在事务提交后直接删除,不需要进行 purge 操作。
  2. update undo log 记录的是对 delete 和 update 操作产生的 undo log。该 undo log 可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除;提交时放入 undo log 链表,等待 purge 线程进行最后的删除。
  • purge 线程
  1. 主要的作用是 清理undo页清理page里面带有Delete_Bit标识的数据行
  2. 在 InnoDB 中,事务中的 Delete 操作实际上并不是真正的删除掉数据行,而是一种Delete Mark操作,在记录上标识Delete_Bit,而不删除记录;
  3. 判断什么时间可以将 undo 页进行清除,请参考系列文章中 MVCC 的讲解。