# 日志 ## 什么是数据库的事务日志?有什么作用? - **事务日志**:是数据库管理系统(DBMS)用来记录所有事务操作(如插入、删除、更新)的日志文件。事务日志用于确保数据库的ACID(原子性、一致性、隔离性、持久性)属性。 - 作用 :- 数据恢复 :在系统崩溃时,通过事务日志恢复未提交或已提交的事务数据。- 回滚操作 :如果事务失败,可以通过日志回滚到事务开始之前的状态。 - **支持事务一致性**:确保事务按照规定的顺序执行,即使发生故障,数据也不会丢失。 ## undo log、redo log、binlog 有什么用? - **undo log(回滚日志)**:是 Innodb 存储引擎层生成的日志,实现了事务中的**原子性**,主要**用于事务回滚和 MVCC**。 - **redo log(重做日志)**:是 Innodb 存储引擎层生成的日志,实现了事务中的**持久性**,主要**用于掉电等故障恢复**; - **binlog (归档日志)**:是 Server 层生成的日志,主要**用于数据备份和主从复制**; ## 什么是undo logo 当事务对数据库进行更新(插入、修改、删除)时,系统会记录相应的`undo log`,以便在事务回滚或系统崩溃时进行数据恢复, 主要用于事务回滚和MVCC。`undo log`记录的信息包括操作类型(插入、删除还是更新),修改前的数据值,被修改的数据的位置,事务标识id等,比如在**更新**一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列**更新为旧值**就好了。 每一次更新操作产生的`undo log `格式都有一个 `roll_pointer` 指针(将undo log 串成一个链表, 链表也被成为版本链)和一个`trx_id`事务id(记录是被哪个事务修改的) - 事务回滚:如果事务在执行过程中出现错误或被用户显式地回滚,系统可以使用`undo log`来还原事务所做的所有修改。通过`undo log`,数据库系统可以逆向执行事务的操作,将数据库还原到事务开始前的状态。 - **实现 MVCC(多版本并发控制)关键因素之一。**MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。 ## 什么是redo log redo log 是物理日志,记录了某个数据页做了什么修改,比如**对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新**,每当执行一个事务就会产生这样的一条或者多条物理日志。在事务提交时,只要先将 redo log 持久化到磁盘即可 ## redo log和undo log的区别是什么 undo log 和 redo log 这两个日志都是 Innodb 存储引擎生成的。 - redo log 记录了此次事务「**完成后**」的数据状态,记录的是更新**之后**的值; - undo log 记录了此次事务「**开始前**」的数据状态,记录的是更新**之前**的值; 事务提交之前发生了崩溃,重启后会通过 undo log 回滚事务,事务提交之后发生了崩溃,重启后会通过 redo log 恢复事务 ## 什么是binlog MySQL 在完成一条更新操作后,Server 层还会生成一条 binlog,等之后事务提交的时候,会将该事物执行过程中产生的所有 binlog 统一写 入 binlog 文件。 binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。 ## redo log和bin log有什么区别 - **适用对象不同**:binlog 是 MySQL 的 Server 层实现的,所有存储引擎都可以使用;redo log 是 Innodb 存储引擎实现的日志。 - **文件格式不同**:redo log 是物理日志,记录的是在某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新。而`binlog` 主要包括三种格式:`Statement`、`Row` 和 `Mixed`。 - **写入方式不同**:binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。redo log是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。 - **用途不同**:binlog 用于备份恢复、主从复制;redo log 用于掉电等故障恢复。 ## 为什么需要两阶段提交 事务提交后,redo log 和 binlog 都要持久化到磁盘,但是这两个是独立的逻辑,可能出现半成功的状态,造成两份日志之间的逻辑不一致。 - **如果在将 redo log 刷入到磁盘之后, MySQL 突然宕机了,而 binlog 还没有来得及写入**。MySQL 重启后,通过 redo log 能将 Buffer Pool 恢复到新值,但是 binlog 里面没有记录这条更新语句,在主从架构中,binlog 会被复制到从库,由于 binlog 丢失了这条更新语句,从库的这一行是旧值,主从不一致。 - **如果在将 binlog 刷入到磁盘之后, MySQL 突然宕机了,而 redo log 还没有来得及写入**。由于 redo log 还没写,崩溃恢复以后这个事务无效,数据是旧值,而 binlog 里面记录了这条更新语句,在主从架构中,binlog 会被复制到从库,从库执行了这条更新语句,这一行字段是新值,与主库的值不一致性。 所以会造成主从环境的数据不一致性。因为 redo log 影响主库的数据,binlog 影响从库的数据,redo log 和 binlog 必须保持一致。 **两阶段提交把单个事务的提交拆分成了 2 个阶段,分别是准备(Prepare)阶段和提交(Commit)阶段**,每个阶段都由协调者(Coordinator)和参与者(Participant)共同完成。 ## 两阶段提交的过程 在 MySQL 的 InnoDB 存储引擎中,开启 binlog 的情况下,MySQL 会同时维护 binlog 日志与 InnoDB 的 redo log,为了保证这两个日志的一致性,MySQL 使用了**内部 XA 事务**,内部 XA 事务由 binlog 作为协调者,存储引擎是参与者。 当客户端执行 commit 语句或者在自动提交的情况下,MySQL 内部开启一个 XA 事务,**分两阶段来完成 XA 事务的提交**。 事务的提交过程有两个阶段,**将 redo log 的写入拆成了两个步骤:prepare 和 commit,中间再穿插写入binlog**: - **prepare 阶段**:将 内部 XA 事务的 ID写入到 redo log,同时将 redo log 对应的事务状态设置为 prepare,然后将 redo log 持久化到磁盘。 - **commit 阶段**:把 内部 XA 事务的 ID写入到 binlog,然后将 binlog 持久化到磁盘,接着调用引擎的提交事务接口,将 redo log 状态设置为 commit,此时该状态并不需要持久化到磁盘,只需要 write 到文件系统的 page cache 成功,只要 binlog 写磁盘成功,redo log 的状态还是 prepare 也没有关系,一样会被认为事务已经执行成功。