{ "topic": "mysql-acid", "type": "fill_blank", "schema_version": "1.0.0", "generated": "2026-09-07T00:00:00+08:00", "questions": [ { "id": "fb-001", "type": "fill_blank", "difficulty": 1, "tags": [ "原子性", "undo log", "InnoDB" ], "question": "InnoDB 保证事务原子性依赖的日志是 ____,它记录的是修改前的旧值,回滚时据此恢复数据。", "answer": [ "undo log" ], "answer_rule": "any", "explanation": "undo log 记录的是事务修改前的旧值(逻辑逆操作)。当事务回滚或崩溃恢复时,InnoDB 依据 undo log 将数据恢复到事务开始前的状态,从而保证原子性(要么全部提交要么全部回滚)。", "source": null, "related": [] }, { "id": "fb-002", "type": "fill_blank", "difficulty": 1, "tags": [ "持久性", "WAL", "redo log" ], "question": "InnoDB 保证持久性采用 Write-Ahead Logging 策略,即在数据页落盘前必须先将对应的 ____ 日志写入磁盘。", "answer": [ "redo log" ], "answer_rule": "any", "explanation": "WAL 的核心是“写日志先行”:任何数据页修改在刷入磁盘之前,必须先把对应的 redo log 记录写入磁盘。这样一旦崩溃,通过重放 redo log 即可恢复未落盘的已提交修改,从而保证持久性。", "source": null, "related": [] }, { "id": "fb-003", "type": "fill_blank", "difficulty": 2, "tags": [ "redo log", "物理日志", "环形缓冲", "InnoDB" ], "question": "InnoDB 的 redo log 在逻辑上是固定大小的环形缓冲,写入是循环的,当写满时会覆盖最 ____ 的日志。", "answer": [ "旧" ], "answer_rule": "any", "explanation": "redo log 由若干固定大小的文件组成环形结构,物理日志循环写入,当文件写满会回绕覆盖最旧(最早写入)的日志记录。因此 redo log 并不记录全部历史,而只保留最近一段时间的重做记录。", "source": null, "related": [] }, { "id": "fb-004", "type": "fill_blank", "difficulty": 2, "tags": [ "redo log", "物理日志", "undo log", "逻辑日志" ], "question": "redo log 记录的是对数据页字节修改的____日志(物理层),而 undo log 记录的是如何“改回旧值”的____日志(逻辑层)。", "answer": [ "物理", "逻辑" ], "answer_rule": "ordered", "explanation": "redo log 属于物理日志,描述对哪个页的哪个位置的字节进行了什么修改,用于崩溃后重放;undo log 属于逻辑日志,记录的是把数据改回旧状态所需的逆操作逻辑。两个空位必须按顺序填“物理 / 逻辑”,所以使用 ordered 规则。", "source": null, "related": [] }, { "id": "fb-005", "type": "fill_blank", "difficulty": 2, "tags": [ "MVCC", "undo log", "隔离性" ], "question": "InnoDB 的 MVCC 通过 undo log 维护行的多____链,配合事务的 ____ 快照决定当前读可见的版本,从而在不加锁的情况下实现一致性的快照读。", "answer": [ "版本", "ReadView" ], "answer_rule": "ordered", "explanation": "InnoDB 通过 undo log 维护行的多版本链,每次更新原记录时旧版本被放入版本链。一致性读(快照读)通过 ReadView(一个事务范围内的可见性判断结构)沿版本链找到当前事务可见的版本,实现高并发的非锁定读。两空位按顺序填“版本 / ReadView”。", "source": null, "related": [] }, { "id": "fb-006", "type": "fill_blank", "difficulty": 3, "tags": [ "崩溃恢复", "redo log", "undo log" ], "question": "InnoDB 崩溃恢复的三阶段为:一、扫描 ____ 确定需要恢复的范围;二、对其中的已提交事务进行 ____;三、对未提交事务用 ____ 进行回滚。", "answer": [ "redo log", "重做", "undo log" ], "answer_rule": "ordered", "explanation": "崩溃恢复流程:先扫描 redo log 确定恢复起点;然后重做(应用)崩溃前已提交但未刷盘的事务,使其修改落到数据页;最后根据两阶段提交状态,对未提交事务用 undo log 回滚,恢复到崩溃前的一致状态。三个空位需按顺序作答。", "source": null, "related": [] }, { "id": "fb-007", "type": "fill_blank", "difficulty": 3, "tags": [ "binlog", "redo log", "两阶段提交" ], "question": "为协调 InnoDB 与 binlog 的一致性,MySQL 对两者采用____阶段提交:先将 redo log 写入____(prepare)阶段,再写 binlog,最后把 redo 标记为 commit。", "answer": [ "两", "prepare" ], "answer_rule": "ordered", "explanation": "MySQL 对 redo log 与 binlog 用两阶段提交(2PC / InnoDB&binlog 内部协调):第一步把 redo log 写入 prepare 阶段(此刻事务处于预提交),第二步写 binlog,第三步将 redo 标记为 commit。崩溃重启时依据 binlog 是否完整来决定事务是提交还是回滚,从而保证两者一致。", "source": null, "related": [] }, { "id": "fb-008", "type": "fill_blank", "difficulty": 2, "tags": [ "innodb_flush_log_at_trx_commit", "持久性" ], "question": "innodb_flush_log_at_trx_commit=1 时,每次事务提交都会调用 ____ 强制把 redo log 刷到磁盘,保证最强的持久性(也最浪费 IO)。", "answer": [ "fsync" ], "answer_rule": "any", "explanation": "取值 1 意味着每次提交时 InnoDB 都调用 fsync 把 redo log 从 OS 缓存强制刷入磁盘,确保提交的事务真正持久化,因此符合严格 ACID 的持久性要求,但会带来较多磁盘同步 IO。", "source": null, "related": [] }, { "id": "fb-009", "type": "fill_blank", "difficulty": 3, "tags": [ "redo log", "binlog", "主从复制", "审计" ], "question": "binlog 是 MySQL ____ 层的逻辑日志,主要用于主从复制、基于时间点恢复(PITR)和 ____;而 redo log 是 InnoDB 引擎层用于崩溃恢复的日志。", "answer": [ "Server", "审计" ], "answer_rule": "any", "explanation": "binlog 由 MySQL 的 Server 层记录逻辑变更,其主要用途包括主从复制(从库重放 binlog)、基于时间点恢复(PITR)以及审计。而 redo log 属于 InnoDB 存储引擎层,只用于崩溃恢复时重做已提交事务。", "source": null, "related": [] }, { "id": "fb-010", "type": "fill_blank", "difficulty": 3, "tags": [ "Buffer Pool", "脏页", "刷盘", "WAL" ], "question": "Buffer Pool 中被修改而未刷盘的数据页称为 ____ 页,InnoDB 会延迟到合适时机(如 CHECKPOINT)才批量 ____ 并将其落盘;由于 redo log 已先行持久化,即使这期间崩溃也能通过重放恢复。", "answer": [ "脏", "刷盘" ], "answer_rule": "ordered", "explanation": "Buffer Pool 中已修改但尚未写回磁盘的页称为脏页。InnoDB 通常在检查点(checkpoint)或后台刷脏线程等时机批量刷盘,而不是每次修改都立即落盘。因为 redo log 已先持久化,脏页即便在刷盘前崩溃,也能通过重放 redo 恢复,这正是 WAL + 延迟刷盘配合的高效设计。", "source": null, "related": [] } ] }