515acbcc7f
Deploy Examination / deploy (push) Successful in 4s
- mysql-acid (35): undo/redo log, WAL, 崩溃恢复三阶段, 两阶段提交 - mysql-transaction-isolation (35): 四隔离级别, 三异常, Read View, 快照读/当前读, next-key lock - redis-persistence (35): RDB/AOF/混合持久化, AOF 重写, vs binlog/redo log - 每子主题: single_choice×10 + fill_blank×10 + short_answer×10 + code_reading×5 - 全部通过 question.schema.json 校验
213 lines
13 KiB
JSON
213 lines
13 KiB
JSON
{
|
||
"topic": "mysql-transaction-isolation",
|
||
"type": "short_answer",
|
||
"schema_version": "1.0.0",
|
||
"generated": "2026-09-07T00:00:00+08:00",
|
||
"questions": [
|
||
{
|
||
"id": "sa-001",
|
||
"type": "short_answer",
|
||
"difficulty": 1,
|
||
"tags": [
|
||
"隔离级别"
|
||
],
|
||
"question": "请列出 MySQL InnoDB 支持的四种事务隔离级别,并按隔离强度从低到高说明它们的名称(中英文均可)。",
|
||
"answer": "四种隔离级别从低到高依次是:READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)、REPEATABLE READ(可重复读,MySQL 默认)、SERIALIZABLE(串行化)。",
|
||
"keywords": [
|
||
"READ UNCOMMITTED",
|
||
"READ COMMITTED",
|
||
"REPEATABLE READ",
|
||
"SERIALIZABLE",
|
||
"默认"
|
||
],
|
||
"scoring_rubric": "正确列出四个名称各 2 分(共 8 分);答对从低到高顺序并指出 REPEATABLE READ 是 MySQL 默认级别得 2 分。",
|
||
"explanation": "四个隔离级别的强度递增:RU 最低允许脏读;RC 只读已提交但出现不可重复读;RR 额外用 MVCC 快照与间隙锁/临键锁防止幻读(MySQL InnoDB 默认);SERIALIZABLE 最高,所有读都加锁串行。"
|
||
},
|
||
{
|
||
"id": "sa-002",
|
||
"type": "short_answer",
|
||
"difficulty": 2,
|
||
"tags": [
|
||
"脏读",
|
||
"不可重复读",
|
||
"幻读"
|
||
],
|
||
"question": "请分别解释事务并发过程中出现的三个异常现象:脏读、不可重复读、幻读。",
|
||
"answer": "脏读:一个事务读到了另一个事务尚未提交(可能回滚)的数据。不可重复读:同一事务内,两次读取同一行数据得到不同的值,因为期间有其他事务修改并提交了该行。幻读:同一事务内,两次执行同一条件查询得到的行数不同,因为另一事务在期间插入或删除了满足条件的行(幻读主要由插入产生)。",
|
||
"keywords": [
|
||
"脏读",
|
||
"不可重复读",
|
||
"幻读",
|
||
"未提交",
|
||
"行数变化"
|
||
],
|
||
"scoring_rubric": "三个现象各 3 分,正确描述现象并点出各自关键特征(脏读=未提交、不可重复读=同一行值变化、幻读=行数变化)得满分;部分答对按要点给分。",
|
||
"explanation": "三者隔离强度递进:脏读最严重(连提交状态都不判断);不可重复读是同一行值变化;幻读是结果集行数变化。SERIALIZABLE 能杜绝全部三种;RR 靠快照读 + 间隙锁基本防住幻读;RC 会发生不可重复读。"
|
||
},
|
||
{
|
||
"id": "sa-003",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"隔离级别",
|
||
"脏读",
|
||
"不可重复读",
|
||
"幻读"
|
||
],
|
||
"question": "请分别说明四种隔离级别各自允许哪些并发异常(脏读、不可重复读、幻读)。",
|
||
"answer": "READ UNCOMMITTED:三种异常都可能出现(脏读、不可重复读、幻读)。READ COMMITTED:不允许脏读,但可能出现不可重复读;对幻读在 MySQL 的语义下基本不设防。REPEATABLE READ:不允许脏读与不可重复读,通过 MVCC 快照读与间隙锁/临键锁基本防止了幻读。SERIALIZABLE:三种异常都不允许,所有读都加锁,事务串行执行。",
|
||
"keywords": [
|
||
"脏读",
|
||
"不可重复读",
|
||
"幻读",
|
||
"各隔离级别",
|
||
"SERIALIZABLE"
|
||
],
|
||
"scoring_rubric": "每个级别正确描述其允许/禁止的异常得 2.5 分(共 10 分),需同时说对允许或禁止哪些现象。",
|
||
"explanation": "隔离级别由低到高允许的异常:RU 全允许;RC 除脏读外其余可发生;RR 基本不允许脏读和不可重复读,幻读由 MVCC+锁基本消除;SERIALIZABLE 全禁止。"
|
||
},
|
||
{
|
||
"id": "sa-004",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"MVCC",
|
||
"版本链",
|
||
"undo log"
|
||
],
|
||
"question": "简述 MySQL InnoDB 的 MVCC(多版本并发控制)是什么?它依赖哪些隐藏列形成版本链?有何作用?",
|
||
"answer": "MVCC 即多版本并发控制,核心思路是让普通 SELECT(快照读)通过读取历史版本与写操作并行且不互斥。每行会隐藏两个列:DB_TRX_ID(最后修改该行的事务 ID)和 DB_ROLL_PTR(指向 undo log 中旧版本的指针),多个历史版本通过 DB_ROLL_PTR 串成一条版本链。快照读依据 Read View 沿版本链找到对当前事务可见的那个版本。作用是实现读写不互斥,提高并发度,并支撑 RC 的读已提交与 RR 的可重复读。",
|
||
"keywords": [
|
||
"MVCC",
|
||
"DB_TRX_ID",
|
||
"DB_ROLL_PTR",
|
||
"版本链",
|
||
"undo log",
|
||
"读写不互斥"
|
||
],
|
||
"scoring_rubric": "说出 MVCC 使读写不互斥(2 分)、两个隐藏列 DB_TRX_ID/DB_ROLL_PTR(各 2 分)、版本链与 undo log(2 分)、讲清作用(2 分)。",
|
||
"explanation": "MVCC 是不加锁并发读的重要机制。undo log 保存旧版本,DB_ROLL_PTR 指向它们,从而把同一行的所有历史版本串成一条版本链。"
|
||
},
|
||
{
|
||
"id": "sa-005",
|
||
"type": "short_answer",
|
||
"difficulty": 4,
|
||
"tags": [
|
||
"Read View",
|
||
"版本链"
|
||
],
|
||
"question": "请描述 Read View 的四个核心字段,并用它们说明 MVCC 判断某行版本可见性的规则。",
|
||
"answer": "Read View 四个字段:m_ids(创建快照这一刻尚未提交的事务 ID 集合)、min_trx_id(m_ids 中最小的事务 ID)、max_trx_id(下一条将要分配的事务 ID 或最大事务 ID)、creator_trx_id(当前创建 ReadView 的事务自身 ID)。可见性判断顺序:一是版本 trx_id 等于 creator_trx_id(自己改的)则可见;二是 trx_id 小于 min_trx_id(该事务已提交且在快照前)则可见;三是 trx_id 大于等于 max_trx_id(快照之后才启动的事务)则不可见;四是 trx_id 处于 m_ids 集合中(尚未提交)则不可见;五是否则可见。若当前版本不可见,则沿 DB_ROLL_PTR 向版本链更旧版本回溯继续判断。",
|
||
"keywords": [
|
||
"m_ids",
|
||
"min_trx_id",
|
||
"max_trx_id",
|
||
"creator_trx_id",
|
||
"可见性"
|
||
],
|
||
"scoring_rubric": "正确写出四个字段各 1 分(共 4 分);可见性规则每条(自己可见、已提交可见、未提交不可见、新事务不可见)约 1.5 分,共约 6 分。",
|
||
"explanation": "ReadView 是 MVCC 可见性判断的核心,关键在于顺序判断:trx_id 小于 min 可见、大于等于 max 不可见、在 m_ids 中不可见。掌握它才能理解 RC 与 RR 的差异。"
|
||
},
|
||
{
|
||
"id": "sa-006",
|
||
"type": "short_answer",
|
||
"difficulty": 4,
|
||
"tags": [
|
||
"隔离级别",
|
||
"Read View"
|
||
],
|
||
"question": "为什么 READ COMMITTED 会发生不可重复读,而 REPEATABLE READ 不会?请从 Read View 的创建时机角度解释。",
|
||
"answer": "因为两者创建 ReadView 的时机不同。READ COMMITTED 下每执行一次普通 SELECT(快照读)都会新建一个 ReadView,因此后一次的 SELECT 能看到其他事务最新提交的数据,导致同一事务内两次读到不同值,即产生不可重复读。REPEATABLE READ 下,事务的第一条 SELECT 才创建 ReadView,之后整个事务内所有快照读都复用这一份 ReadView,其他事务的提交对这份固定快照不可见,因此多次读取结果一致,即满足可重复读。",
|
||
"keywords": [
|
||
"新 ReadView",
|
||
"复用",
|
||
"每次 SELECT",
|
||
"不可重复读"
|
||
],
|
||
"scoring_rubric": "指出 RC 每次都新建 ReadView(3 分)、RR 复用首次的 ReadView(3 分)、并正确连接到不可重复读与可重复读现象(4 分)。",
|
||
"explanation": "这正是 RC 与 RR 在 MVCC 上最本质的区别:ReadView 的创建时机与复用策略决定了可见版本集合的刷新频率。"
|
||
},
|
||
{
|
||
"id": "sa-007",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"快照读",
|
||
"当前读"
|
||
],
|
||
"question": "请解释 MySQL 中快照读与当前读的区别,并各举一个例子。",
|
||
"answer": "快照读(Snapshot Read,也称一致性非锁定读):普通的 SELECT,不加任何锁,通过 MVCC 读取一致性快照(依据 ReadView),不会因其它事务的写操作而阻塞。例子:SELECT * FROM t(不带 FOR UPDATE 或 LOCK IN SHARE MODE)。当前读(Current Read):读取数据的最新已提交版本,并在读取后被访问的影响记录加锁,属于加锁读。例子:SELECT ... FOR UPDATE(排X锁)、SELECT ... LOCK IN SHARE MODE(共享锁),以及 UPDATE、DELETE、INSERT 语句本身就是当前读。核心区别:快照读走 MVCC 不加锁,当前读走锁、读最新提交数据。",
|
||
"keywords": [
|
||
"快照读",
|
||
"当前读",
|
||
"MVCC",
|
||
"加锁",
|
||
"FOR UPDATE"
|
||
],
|
||
"scoring_rubric": "将快照读解释为 MVCC 不加锁(3 分)、当前读解释为加锁读最新(3 分)、各举正确例子(4 分)。",
|
||
"explanation": "快照读与当前读是理解 MySQL 并发读与锁行为的关键。注意 UPDATE/DELETE/INSERT 必须读最新提交并加锁,避免基于旧数据覆盖。"
|
||
},
|
||
{
|
||
"id": "sa-008",
|
||
"type": "short_answer",
|
||
"difficulty": 4,
|
||
"tags": [
|
||
"临键锁",
|
||
"间隙锁",
|
||
"行锁",
|
||
"幻读"
|
||
],
|
||
"question": "解释 Record Lock、Gap Lock、Next-Key Lock 三者的区别,以及它们如何配合防止幻读。",
|
||
"answer": "Record Lock(行锁):只锁定某一条具体记录,阻止对该行的修改。Gap Lock(间隙锁):锁定某个索引区间内的空隙(不含已存在的记录),阻止其他事务在这个空隙内插入新行,但它本身不保护具体记录,且间隙锁之间通常不互相排斥。Next-Key Lock(临键锁):是 Record Lock 与 Gap Lock 的组合,防护左开右闭区间,同时锁定记录本身及其之前的间隙。防幻读机制:REPEATABLE READ 下的当前读(如 SELECT ... FOR UPDATE、UPDATE、DELETE)会加 Next-Key 锁,把范围内所有可能插入的位置锁住,从而阻止并发事务插入新行,避免出现幻行。",
|
||
"keywords": [
|
||
"Record Lock",
|
||
"Gap Lock",
|
||
"Next-Key Lock",
|
||
"防幻读",
|
||
"间隙"
|
||
],
|
||
"scoring_rubric": "分别描述三种锁的特征各 2 分(共 6 分);解释临键锁如何通过间隙锁阻止插入防幻方 4 分。",
|
||
"explanation": "Next-Key Lock 等于 Record Lock 加 Gap Lock,是 RR 下当前读防幻读的关键。间隙锁专为堵插入而设计。"
|
||
},
|
||
{
|
||
"id": "sa-009",
|
||
"type": "short_answer",
|
||
"difficulty": 2,
|
||
"tags": [
|
||
"隔离级别"
|
||
],
|
||
"question": "如果业务需要最严格的隔离保证(不允许脏读、不可重复读、幻读),你会选择哪个隔离级别?代价是什么?",
|
||
"answer": "选择 SERIALIZABLE(串行化)。它是最高隔离级别,会强制将所有普通 SELECT 也转为加锁读(等价于给读取范围加共享锁并配合临键锁/间隙锁),读写完全互斥、事务近乎串行,从而杜绝脏读、不可重复读和幻读。代价是并发度大幅下降,读操作之间也互斥,容易引发锁竞争、阻塞甚至死锁,吞吐量明显低于其他级别;因此若非必要一般不直接使用,可在业务层用更精细的锁或优化 SQL 替代。",
|
||
"keywords": [
|
||
"SERIALIZABLE",
|
||
"串行化",
|
||
"加锁读",
|
||
"并发下降",
|
||
"代价"
|
||
],
|
||
"scoring_rubric": "答对选择 SERIALIZABLE(3 分);说明其加锁机制保证全隔离(3 分);指出以并发与性能为代价(4 分)。",
|
||
"explanation": "SERIALIZABLE 是安全但昂贵的:全部读都加锁,牺牲了 MVCC 的读写并发优势,只适合极苛刻场景。"
|
||
},
|
||
{
|
||
"id": "sa-010",
|
||
"type": "short_answer",
|
||
"difficulty": 3,
|
||
"tags": [
|
||
"MVCC",
|
||
"隔离级别",
|
||
"快照读"
|
||
],
|
||
"question": "InnoDB 的 MVCC 为什么在 READ COMMITTED 与 REPEATABLE READ 下都能工作?两者基于 MVCC 提供的可读行为有何区别?",
|
||
"answer": "MVCC 是 InnoDB 中通过每行版本链(DB_TRX_ID + DB_ROLL_PTR)与 Read View 判断可见性的通用机制,因此在 RC 与 RR 两个隔离级别下都会启用 MVCC。行为区别:RC 每次普通 SELECT 新建 ReadView,能读其他事务最新已提交的版本,产生不可重复读;RR 在事务第一条 SELECT 建立 ReadView 并全程复用,因此整个事务内快照一致,满足可重复读。两者 MVCC 基础设施相同,但 ReadView 的创建/复用规则不同,导致对外行为不同。",
|
||
"keywords": [
|
||
"MVCC",
|
||
"ReadView",
|
||
"RC 每次",
|
||
"RR 复用",
|
||
"可重复读"
|
||
],
|
||
"scoring_rubric": "说明 MVCC 在两个级别均启用(3 分);RC 每次新建 ReadView 的行为(3 分);RR 每次复用 ReadView 的行为(4 分)。",
|
||
"explanation": "MVCC 是基础,真正区分 RC/RR 语义的是 ReadView 的创建时机与复用策略,理解这点就掌握了 MySQL 并发读的核心。"
|
||
}
|
||
]
|
||
} |