开发需了解的知识:MySQL RedoLog/UndoLog具体存储内容

在数据库中,Redo LogUndo Log 是两种日志机制,分别用于不同的目的,保障数据的一致性、完整性和恢复能力。

1. 定义和作用

  • Redo Log(重做日志):
    Redo Log 是记录已经提交的事务对数据库的修改操作,主要用于崩溃恢复 。在数据库出现故障时,Redo Log 能帮助数据库重做(恢复)已经提交但尚未写入数据文件的操作,确保数据一致性。
  • Undo Log(回滚日志):
    Undo Log 记录未提交事务的反向操作 ,用于事务回滚。如果某个事务需要回滚(比如用户取消了操作或出现错误),数据库可以通过 Undo Log 恢复到事务之前的状态,确保数据库的一致性。

2. 记录内容

  • Redo Log:
    Redo Log 记录的是对数据的物理修改 ,即某个事务对数据页的具体修改内容。这种日志记录的是如何将数据库修改成新的状态,通常是针对已提交事务的变化。
  • Undo Log:
    Undo Log 记录的是相反操作 ,即撤销某个未提交事务所做的修改。例如,如果事务进行了数据插入操作,Undo Log 会记录删除该数据的操作。它保存的是事务在数据库中的初始状态,方便在需要时进行回滚。

3. 触发时机

  • Redo Log:
    Redo Log 会在事务修改数据时被立即写入,用于记录这些修改操作。即使数据尚未真正写入磁盘,Redo Log 也已经记录了这些变更,以便在数据库崩溃后能够重新执行这些修改。
  • Undo Log:
    Undo Log 在事务开始时就开始记录每一步操作的反向操作,确保在事务回滚时可以正确恢复到事务之前的状态。这是为了保证事务的原子性。

4. 恢复场景

  • Redo Log:
    当数据库崩溃或意外关闭时,通过 Redo Log 进行恢复。它可以将已提交的事务重新应用到数据库中,即使这些修改还未写入磁盘。
  • Undo Log:
    当事务被取消或出现错误时,通过 Undo Log 进行回滚操作。它可以将数据库恢复到事务开始之前的状态,保证数据的完整性。

5. 性能影响

  • Redo Log:
    Redo Log 通过记录已经提交事务的修改操作,减少了频繁写入数据文件的压力,因此可以提高数据库的写入性能。然而,为保证事务持久性,Redo Log 需要快速写入。
  • Undo Log:
    Undo Log 需要记录每个未提交事务的逆操作,回滚操作越多,Undo Log 所占用的空间就越大。当回滚事务增多时,数据库性能可能受到影响。

6. 数据持久性

  • Redo Log:
    确保提交的事务即使在数据库崩溃后也能恢复,体现了事务的持久性(Durability)。数据库会先写入 Redo Log,再提交事务,以确保数据不会丢失。
  • Undo Log:
    确保事务未提交前,所有的操作都可以撤销,体现了事务的原子性(Atomicity)。通过 Undo Log,未提交的事务可以被撤回,不会影响数据库的其他部分。

7. 使用场景

  • Redo Log:
    主要用于崩溃恢复。在系统故障或断电后,可以根据 Redo Log 重新执行已提交的事务操作,以保证数据的完整性。
  • Undo Log:
    主要用于事务回滚。当用户取消操作或出现事务冲突时,Undo Log 通过撤销未提交的修改,确保数据回到正确的状态。

总结

对比项 Redo Log(重做日志) Undo Log(回滚日志)
作用 崩溃恢复,重做已提交的事务修改 事务回滚,撤销未提交的事务操作
记录内容 数据修改的正向操作(物理变更) 事务的反向操作(撤销步骤)
触发时机 事务提交或数据修改时记录 事务开始时记录逆操作
恢复场景 系统崩溃后,恢复已提交数据 事务失败或取消时,回滚未提交数据
数据持久性 保证已提交事务的数据持久化 保证事务的原子性,可撤销未提交操作
使用场景 崩溃恢复,重做已提交修改 事务回滚,撤销未提交的事务

简而言之,Redo Log 主要用于恢复已提交的事务 ,而 Undo Log 则用于回滚未提交的事务,共同保障了数据库的可靠性和一致性。

Redo Log具体记录内容

Redo Log 记录的是事务对数据库的物理修改,其主要目的是在数据库崩溃或异常时,帮助系统将已经提交但尚未持久化的数据恢复到最新状态。它的记录内容非常具体,主要包括事务的修改操作以及这些操作所涉及的数据库页、块等。为了更好地理解,以下是一个具体的例子:

场景假设

假设我们有一张名为 employees 的表,包含两列:idsalary。我们要执行一个事务,更新员工的薪水。

sql 复制代码
BEGIN;
UPDATE employees SET salary = salary + 500 WHERE id = 1001;
COMMIT;

Redo Log 记录的内容

当执行上述事务时,Redo Log 会记录事务对数据库的修改。具体的内容可以分为以下几个部分:

  1. 事务的开始标记: 在事务开始时,Redo Log 会记录一个事务开始的标记。它表明一个新的事务正在进行,通常包括事务的唯一标识符(事务ID)。

    例如:

    sql 复制代码
    BEGIN TRANSACTION: TXID = 12345
  2. 物理修改操作记录: 当 SQL 更新操作被执行时,数据库会查找到目标数据所在的数据页(通常数据按页存储,每页固定大小),并且修改该页中相关数据的值。

    在这个例子中,事务要修改 employees 表中 id = 1001 的员工记录的 salary。数据库会定位到存储该记录的页面(假设是数据页 PAGE 5432),并修改该记录。

    Redo Log 会记录:

    • 修改的数据页ID (例如 PAGE 5432
    • 该页中被修改的具体字节偏移(表明是哪个字段被修改)
    • 旧值和新值(或者只记录新值,取决于具体的数据库实现)

    例如:

    yaml 复制代码
    MODIFY PAGE: PAGE 5432, OFFSET 200, OLD VALUE: 5000, NEW VALUE: 5500

    这表示在 PAGE 5432 的偏移量为 200 处,salary5000 被修改为 5500

  3. 事务的提交标记: 当事务执行到 COMMIT 时,Redo Log 会记录一个事务提交的标记,表示该事务已提交,所有的修改操作都是持久的。如果数据库崩溃,恢复机制会根据这个提交标记来重做该事务的修改。

    例如:

    sql 复制代码
    COMMIT TRANSACTION: TXID = 12345

Redo Log 恢复场景

假设在该事务提交后,数据尚未写入磁盘,但数据库突然崩溃了。在重启数据库时,恢复机制会通过 Redo Log 进行如下操作:

  1. 通过 Redo Log 找到事务 TXID = 12345 的修改记录。
  2. 发现该事务已经提交,所以需要重做事务的修改。
  3. 根据 Redo Log 记录的内容,找到 PAGE 5432,并将偏移量 200 处的 salary 值恢复为 5500

Redo Log 记录的内容详解

Redo Log 具体记录的内容,通常包括以下信息:

  • 事务ID(Transaction ID, TXID): 用于唯一标识事务。
  • 操作类型: 包括事务开始、提交或修改数据页。
  • 表或页面的唯一标识符: 记录被修改的表或数据页的ID。
  • 数据页的偏移量: 被修改的具体数据位置,以字节偏移量表示。
  • 修改的内容: 包括修改前的旧值、修改后的新值(有时Redo Log只记录新值)。

总结

Redo Log 通过记录物理级别的修改(例如某个数据页的具体字节变化),保证了即使数据库发生崩溃,已提交的事务也不会丢失。它记录了事务从开始到提交的所有操作,确保数据库能够在崩溃后恢复一致性。

Undo Log 记录的是数据库中事务未提交的反向操作,它的主要目的是支持事务回滚。当事务在执行过程中出现问题或用户主动取消操作时,Undo Log 能帮助数据库撤销未提交的更改,将数据恢复到修改之前的状态。

Undo Log 的基本记录内容

Undo Log 记录的是事务进行的每一个修改前的旧值。通过这些旧值,在事务需要回滚时,数据库可以撤销未提交的修改,将数据恢复为修改前的状态。

举例说明

假设我们有一张名为 employees 的表,其中包含两列:idsalary。我们进行一个事务来更新某位员工的薪水,但在事务提交前发生了错误,导致需要回滚。

场景
sql 复制代码
BEGIN;
UPDATE employees SET salary = salary + 500 WHERE id = 1001;
-- 某种原因导致事务失败或被取消
ROLLBACK;
Undo Log 的记录过程
  1. 事务开始: 在事务开始时,数据库不会立即记录在 Undo Log 中,而是等待具体的修改操作发生。

  2. 修改操作的 Undo Log 记录: 当我们执行 UPDATE employees SET salary = salary + 500 WHERE id = 1001 时,数据库会先记录下修改前的数据,以便在回滚时可以还原。具体地,数据库会记录该员工的 salary 修改前的值,假设原来的 salary = 5000,修改后的新值是 5500

    Undo Log 会记录:

    • 修改前的旧值 (即 salary = 5000
    • 修改的位置(包括数据页和偏移量,类似于 Redo Log 中的记录方式)

    示例记录如下:

    yaml 复制代码
    UNDO LOG: PAGE 5432, OFFSET 200, OLD VALUE: 5000

    这条记录表明,如果回滚,数据库应该将数据页 PAGE 5432 的偏移量 200 处的值恢复为 5000,即回滚前的薪水。

  3. 回滚操作: 当事务执行 ROLLBACK 时,数据库会查找 Undo Log,按照逆序 撤销该事务做出的修改。这里,Undo Log 会根据记录,将员工的薪水从 5500 恢复到 5000,使数据库回到事务开始时的状态。

    回滚过程会依次撤销每一项操作。对于这个示例,数据库将会:

    • 找到 PAGE 5432,恢复偏移量 200 处的值为 5000,即回滚薪水的增加操作。
  4. 事务结束: 当事务完全回滚后,数据库会删除与该事务相关的 Undo Log 记录,以释放空间。

Undo Log 记录的内容详解

Undo Log 通常记录以下几项内容:

  • 事务ID(Transaction ID, TXID): 标识当前事务。
  • 操作类型: 记录修改类型(如 INSERT、UPDATE、DELETE)。
  • 表或数据页标识符: 记录被修改的表或页的标识符。
  • 修改的位置: 指出具体数据的位置(例如数据页ID、偏移量等)。
  • 旧值: 记录修改前的数据(用于回滚操作)。

更复杂的场景

假设我们进行一次插入操作,并且在之后回滚。Undo Log 在这种情况下也会记录下反向操作。

sql 复制代码
BEGIN;
INSERT INTO employees (id, salary) VALUES (1002, 3000);
ROLLBACK;

在这种场景下,Undo Log 会记录插入了新的记录。为了能够回滚,Undo Log 必须记录删除新插入记录的操作。也就是说,Undo Log 会记载:

sql 复制代码
UNDO LOG: DELETE ROW WHERE id = 1002

当事务回滚时,Undo Log 会执行这个删除操作,移除新插入的记录 id = 1002,使数据库回到插入前的状态。

总结

Undo Log 主要用于事务回滚,它记录了每个事务操作前的旧值或相应的反向操作。例如:

  • UPDATE 操作中,Undo Log 记录修改前的值。
  • INSERT 操作中,Undo Log 记录要删除新插入的行。
  • DELETE 操作中,Undo Log 记录要恢复的被删除数据。

Undo Log 使得数据库能够轻松地将未提交的事务进行回滚,恢复数据一致性,确保事务的原子性

思考题:假如插入了id=1002数据被回滚了,再次插入id是多少

如果插入了 id=1002 的数据后进行了回滚,那么该条记录实际上并没有持久化到数据库中,也就是说 id=1002 并不存在于数据库中。

当你再次插入 一条记录时,id 的生成方式取决于主键生成策略,通常有以下几种情况:

1. 手动插入 id

如果 id 是由用户手动指定的,那么回滚后再次插入时,你可以再次使用 id=1002,因为之前的插入操作并未成功,1002 这个值并没有占用。例如:

sql 复制代码
INSERT INTO employees (id, salary) VALUES (1002, 3000);

在这种情况下,回滚后你可以再次使用 1002 作为 id,因为它从未真正被插入到数据库中。

2. 自增主键(AUTO_INCREMENT)

如果 id 是使用数据库的自增主键 (如 MySQL 的 AUTO_INCREMENT),情况会有所不同。自增主键的值是由数据库自动生成的,并且一旦生成,即使回滚,主键计数器也不会回退 。换句话说,即使事务回滚,自增主键生成的 id=1002 也已经占用了这个编号。

  • 第一次插入: id=1002 被分配,但由于回滚,记录被撤销。
  • 第二次插入: 自增主键会继续从上次分配的 id 之后进行编号,因此新的 id 会是 1003

例如,使用 AUTO_INCREMENT 时:

sql 复制代码
INSERT INTO employees (salary) VALUES (3000);

在回滚后,下一次插入的 id 会是 1003,而不是 1002,因为 1002 已经被分配过了,虽然事务被回滚了,但 AUTO_INCREMENT 不会重用该编号。

3. 其他主键生成策略

如果数据库使用了其他主键生成策略(如 PostgreSQL 的序列 SEQUENCE 或 UUID),结果也取决于策略的设计:

  • SEQUENCE 类似于 AUTO_INCREMENT,即一旦序列值被分配,即使事务回滚,序列也不会重用该值。
  • UUID 则是每次都会生成唯一的标识符,不受回滚影响,下一次插入时会生成一个全新的 UUID。

总结

  • 如果 id 是手动指定的,回滚后可以重新使用 1002
  • 如果 id 是由自增主键生成的,回滚后下一次插入的 id 会是 1003,而不是 1002,因为自增主键不会回退。
  • 其他主键策略(如序列、UUID)会根据各自的规则生成下一个唯一值。
相关推荐
java1234_小锋4 分钟前
使用 RabbitMQ 有什么好处?
java·开发语言
TangKenny17 分钟前
计算网络信号
java·算法·华为
肘击鸣的百k路18 分钟前
Java 代理模式详解
java·开发语言·代理模式
城南vision24 分钟前
Docker学习—Docker核心概念总结
java·学习·docker
wyh要好好学习31 分钟前
SpringMVC快速上手
java·spring
尢词33 分钟前
SpringMVC
java·spring·java-ee·tomcat·maven
Mr. zhihao40 分钟前
享元模式在 JDK 中的应用解析
java·享元模式
茶馆大橘43 分钟前
微服务系列五:避免雪崩问题的限流、隔离、熔断措施
java·jmeter·spring cloud·微服务·云原生·架构·sentinel
wrx繁星点点43 分钟前
享元模式:高效管理共享对象的设计模式
java·开发语言·spring·设计模式·maven·intellij-idea·享元模式
真的想不出名儿1 小时前
Java基础——反射
java·开发语言