{ "topic": "mysql-transaction-isolation", "type": "single_choice", "schema_version": "1.0.0", "generated": "2026-09-07T00:00:00+08:00", "questions": [ { "id": "sc-001", "type": "single_choice", "difficulty": 1, "tags": [ "隔离级别", "脏读" ], "question": "MySQL InnoDB 默认的事务隔离级别是下列哪一项?", "options": { "A": "READ UNCOMMITTED", "B": "READ COMMITTED", "C": "REPEATABLE READ", "D": "SERIALIZABLE" }, "answer": "C", "explanation": "MySQL InnoDB 存储引擎的默认隔离级别是 REPEATABLE READ(可重复读)。在该级别下,同一事务内多次普通 SELECT 读取到的数据是一致的(快照读复用 Read View),并通过 MVCC + 间隙锁/临键锁在一定程度上防止了幻读。注意:虽然 InnDB 默认是可重复读,但 MySQL 官方文档同时指出 InnoDB 在该级别下结合唯一索引的临键锁几乎已能达到可串行化效果。", "source": null, "related": [] }, { "id": "sc-002", "type": "single_choice", "difficulty": 1, "tags": [ "脏读" ], "question": "下列关于「脏读」的描述,正确的是?", "options": { "A": "事务 A 读到事务 B 已提交的新数据", "B": "事务 A 读到事务 B 尚未提交(可能回滚)的数据", "C": "同一事务内两次读同一行的值发生变化", "D": "同一事务内满足条件的行数发生变化" }, "answer": "B", "explanation": "脏读(Dirty Read)指一个事务读取到了另一个事务尚未提交的数据。由于该事务可能回滚,读到的值很可能是『脏』的、最终不存在的数据,因此称为脏读。选项 A 描述的是已提交数据,不算脏读;选项 C 是不可重复读;选项 D 是幻读。脏读只在最低的 READ UNCOMMITTED 隔离级别下发生。", "source": null, "related": [] }, { "id": "sc-003", "type": "single_choice", "difficulty": 2, "tags": [ "隔离级别", "不可重复读" ], "question": "在 READ COMMITTED(读已提交)隔离级别下,下列哪种现象仍然可能发生?", "options": { "A": "脏读", "B": "不可重复读", "C": "幻读", "D": "以上都不会发生" }, "answer": "B", "explanation": "READ COMMITTED 通过只读已提交的数据消除了脏读,但每次普通 SELECT 都会新建 ReadView,因此同一事务内两次读取同一行,若期间有其他事务提交了更新,读取的值会不同,即产生不可重复读。幻读在某些定义下在 RC 级别并不存在(RC 只会插入符合条件的新行且事务无法保证前者被读出来的行数),但按照 MySQL 隔离级别标准,RC 允许不可重复读;选项 C 幻读严格发生在 REPEATABLE READ 以下,RC 级别在并发插入时也会出现类似幻读现象,但本题考察的核心隔离级别行为差异,正确答案选 B。", "source": null, "related": [] }, { "id": "sc-004", "type": "single_choice", "difficulty": 2, "tags": [ "幻读", "间隙锁", "临键锁" ], "question": "REPEATABLE READ(可重复读)隔离级别下,InnoDB 主要依靠什么机制来防止幻读?", "options": { "A": "完全是普通的行锁 Record Lock", "B": "MVCC 快照读 + 间隙锁(Gap Lock)/ 临键锁(Next-Key Lock)", "C": "每次查询都加全表锁", "D": "完全依靠组合唯一约束" }, "answer": "B", "explanation": "幻觉读(Phantom Read)是指同一事务内,满足相同条件的行数发生了增减(通过其他事务的插入实现)。InnoDB 在 REPEATABLE READ 下通过两条路径防止幻读:(1) 普通 SELECT 走快照读的 MVCC,读到的是一次快照;(2) 当前读(SELECT ... FOR UPDATE / UPDATE / DELETE)使用间隙锁 Gap Lock 与临键锁 Next-Key Lock(行锁 + 间隙锁)锁定区间,阻止并发事务在区间内插入新行。选项 A 忽略了间隙锁部分,选项 C 不准确,D 与本题无关。", "source": null, "related": [] }, { "id": "sc-005", "type": "single_choice", "difficulty": 2, "tags": [ "隔离级别", "脏读" ], "question": "下列哪个隔离级别允许脏读发生?", "options": { "A": "READ UNCOMMITTED", "B": "READ COMMITTED", "C": "REPEATABLE READ", "D": "SERIALIZABLE" }, "answer": "A", "explanation": "READ UNCOMMITTED(读未提交)是对隔离要求最低的级别,它允许事务读取到其他事务尚未提交的数据,即允许脏读。该级别虽然并发性能较高,但语义上几乎难以保证正确性,因此上生产环境通常不用它。BCD 三个级别都不允许脏读。", "source": null, "related": [] }, { "id": "sc-006", "type": "single_choice", "difficulty": 3, "tags": [ "MVCC", "Read View", "版本链" ], "question": "下列关于 MySQL InnoDB MVCC 的说法,正确的是?", "options": { "A": "MVCC 使得读写操作完全相互排斥,性能下降", "B": "每一行数据通常隐藏 DB_TRX_ID(最后修改事务 ID)与 DB_ROLL_PTR(指向 undo log 旧版本)两个隐藏列,共同构成版本链", "C": "MVCC 只在 SERIALIZABLE 隔离级别下有效", "D": "每次 UPDATE 都会覆盖旧版本数据,不保留历史版本" }, "answer": "B", "explanation": "MVCC(多版本并发控制)的核心思想是让普通读(快照读)与写操作不用互相阻塞,从而显著提高并发性能,故 A 错误。InnoDB 会为每行隐藏 DB_TRX_ID(最后修改该行的事务 ID)与 DB_ROLL_PTR(指向 undo log 中旧版本的指针),由此形成一条版本链,快照读通过与 ReadView 比对找到可见的版本,故 B 正确。MVCC 在 READ COMMITTED 与 REPEATABLE READ 级别下都发挥作用,并非只在 SERIALIZABLE 下有效,故 C 错误。UPDATE 实际上会给行生成新版本并通过 DB_ROLL_PTR 指向旧版本,并不会无条件覆盖历史版本,故 D 错误。", "source": null, "related": [] }, { "id": "sc-007", "type": "single_choice", "difficulty": 3, "tags": [ "Read View", "快照读" ], "question": "关于 MySQL 中快照读(Snapshot Read)与当前读(Current Read)的说法,正确的是?", "options": { "A": "普通 SELECT 属于当前读,会加锁", "B": "SELECT ... FROM t FOR UPDATE 属于快照读,走 MVCC 不加锁", "C": "普通 SELECT 属于快照读,走 MVCC 不加锁;SELECT ... FOR UPDATE / UPDATE / DELETE / INSERT 属于当前读,走锁读最新已提交数据", "D": "快照读和当前读都会对读取的行加排他锁" }, "answer": "C", "explanation": "快照读(快照读)即普通 SELECT,它借助 MVCC 读取某个一致性快照,不加锁,因此称为非锁定读;而当前读是指需要读取数据最新已提交版本并在读取后对该行加锁的读取方式,包括 SELECT ... FOR UPDATE(加排他锁)、SELECT ... LOCK IN SHARE MODE(加共享锁)、以及 UPDATE / DELETE / INSERT。快照读在 REPEATABLE READ 下复用同一 ReadView,实现可重复读;当前读无论隔离级别如何都会读到最新已提交(或本事务)的数据,并可能触发间隙锁等。故 C 正确。", "source": null, "related": [] }, { "id": "sc-008", "type": "single_choice", "difficulty": 4, "tags": [ "Read View", "版本链", "MVCC" ], "question": "假设 Read View 的快照包含:m_ids = {100, 101},min_trx_id = 100,max_trx_id = 102,creator_trx_id = 99。对于一个事务 ID 为 100 的事务修改过的数据行,该快照读时该行的可见性判断是?", "options": { "A": "可见,因为 100 小于 max_trx_id", "B": "不可见,因为 100 在 m_ids 集合中(尚未提交)", "C": "可见,因为在 m_ids 中属于已提交事务", "D": "不可见,因为没有该行数据" }, "answer": "B", "explanation": "MVCC Read View 可见性判断规则依次为:① 当前事务自己修改的(叶子 trx_id == creator_trx_id)可见;② trx_id < min_trx_id 说明已早期提交,可见;③ trx_id >= min_trx_id 不可见;④ trx_id 在 m_ids 集合中说明该事务尚未提交,不可见;⑤ 否则可见。本题中 trx_id = 100 恰好等于 min_trx_id 且在 m_ids 集合中,属于未提交事务,因此该行对当前 Read View 不可见(但是对自身事务可见)。B 正确。", "source": null, "related": [] }, { "id": "sc-009", "type": "single_choice", "difficulty": 4, "tags": [ "隔离级别", "Read View" ], "question": "下列关于 READ COMMITTED 与 REPEATABLE READ 在 ReadView 上的区别,陈述正确的是?", "options": { "A": "RC 每次普通查询都新建 ReadView,RR 在事务第一条 SELECT 时建立 ReadView 并复用", "B": "RC 在事务开始时建立 ReadView,RR 每次查询都新建", "C": "二者都复用首个 ReadView", "D": "二者每次查询都新建 ReadView" }, "answer": "A", "explanation": "ReadView 的创建时机是 RC 与 RR 的关键差异:READ COMMITTED 下每执行一次普通 SELECT(快照读)都会新建一个 ReadView,因此可以读到其他事务最新提交的数据,产生不可重复读;REPEATABLE READ 下,事务第一条 SELECT(或数据变更触发时)构建 ReadView,之后整个事务中所有快照读都复用这份 ReadView,从而实现对同一条快照的一直读,满足可重复读。这也是 InnoDB 中 RR 通过快照实现可重复读的基础。", "source": null, "related": [] }, { "id": "sc-010", "type": "single_choice", "difficulty": 2, "tags": [ "隔离级别", "脏读", "临键锁" ], "question": "SERIALIZABLE(串行化)隔离级别与 MySQL InnoDB 实现中最相符的描述是?", "options": { "A": "仅对写操作加锁,读完全不加锁", "B": "使所有普通 SELECT 也被强制转为加锁读(等价当前读),并对范围加临键锁,实时上所有读写操作都是互斥串行执行", "C": "该级别也依赖 MVCC 快照读实现幻读防止", "D": "只阻止脏读,不阻止幻读,所有读写通用 CS 频繁冲突" }, "answer": "B", "explanation": "SERIALIZABLE 是最严格的隔离级别,它本质上将所有普通 SELECT 也自动升级为加锁读(等价于 SELECT ... LOCK IN SHARE MODE 的行为),读写完全相互阻塞,并配合间隙锁/临键锁串行化整个事务执行,因此既不会出现脏读、不可重复读,也不会出现幻读。选项 C 表面上在说 MVCC,但该级别下快照读会被锁读替代,不再单纯依赖 MVCC 快照,因此不准确;选项 D 错误。", "source": null, "related": [] } ] }