今天是我准备的第四十七天,早上打开笔记,刚想复习前两天背过的 MySQL,就发现事务隔离级别那一栏又有点模糊了。这种感觉挺搞心态的:明明每次都背得很熟,第二天却像被格式化了硬盘一样,只剩下“好像学过”。但说实话,MySQL 确实是实习面试里的大重点,后端要问、数据岗要问,甚至客户端实习都可能被问到数据库基础,躲不掉。我决定换个思路,不再死记硬背,而是把今天定为“MySQL八股背诵第四天 + 一道堆算法题”的复盘现场:把事务、索引、锁、日志、MVCC 串成一条线,再刷一道高频堆题,看看能不能把“背了会忘”的问题真正解决。
1. 第47天的复习现场:为什么MySQL背了三天还是会忘
1.1 面试官问MySQL,到底在问什么
如果你去搜“mysql面试题”,会发现前排永远是事务、索引、锁、MVCC、日志优化这些内容。这不是面试官闲着没事干,而是他们想用最短的时间判断你的基础到底扎不扎实。数据库是几乎所有业务系统的底座,一个实习生写出来的 SQL 会不会走索引、能不能避免死锁,直接影响线上稳定性。所以面试官问 MySQL,往往不是想听你背诵《高性能MySQL》目录,而是想看两件事:第一,你有没有系统学过数据库核心机制;第二,你能不能把知识点讲成“为什么”。
就我观察到的情况,后端实习岗位的 MySQL 问题通常从浅到深分三层。第一层是语法和基础概念,比如“left join 和 inner join 区别”“where 和 having 区别”,这个属于送分题。第二层是索引和 SQL 优化,比如“为什么用了索引查询还是慢”“联合索引最左前缀是怎么失效的”。第三层才是拉开差距的地方,比如“RR 隔离级别下一条 update 会加哪些锁”“redo log 和 binlog 的两阶段提交是干什么的”。前两层如果背不下来,基本挂;第三层如果背下来了但讲不透,一样挂。
所以我不太赞成把八股两个字看成贬义。对实习面试来说,八股就是基础知识的浓缩检查清单。你不需要每个冷门参数都背,但核心机制必须形成条件反射。问题的关键从来不是“要不要背”,而是“怎么背才不容易忘”。
1.2 背了又忘的根因:知识是孤立的
我前三天背 MySQL 的方式特别原始:打开一篇很长的总结帖,从头到尾划重点,然后默念,关掉笔记觉得自己天下无敌,晚上睡前再想,只记得大概。今天早上想回忆“可重复读是怎么解决幻读的”,脑子里的画面居然是一大段加粗文字,而不是一套完整的推演逻辑。这其实就是记忆科学里很典型的“编码-存储-提取”问题:你只是把信息编码进了短期记忆,没有和已有知识建立连接,提取线索少,过了一夜就断片。
打个比方,就像一个乱糟糟的衣柜,衣服全塞进去了,但没有任何分类。你确实“拥有”这些知识,可要用的时候找不到。MySQL 的知识点环环相扣,事务的隔离级别要依赖锁和 MVCC,索引失效要依赖 B+ 树的排序规则,redo log 和 binlog 的一致性要依赖崩溃恢复流程。如果每一个知识点都是孤岛,记起来当然费劲,忘起来当然飞快。今天我把复习目标从“背下清单”换成了“串成链路”,先搭骨架再填细节,效果比前几天好不少。
1.3 今天的MySQL核心复习清单
为了不让一天淹没在十多个细碎知识点里,我给自己圈了五个模块,每个模块只回答一个核心问题:
| 模块 | 核心问题 | 今天要做到的程度 |
|---|---|---|
| 事务与隔离级别 | ACID 到底由什么机制保证? | 能用自己的话解释,不背定义 |
| 索引 | B+ 树为什么适合索引?联合索引在什么场景失效? | 能从排序和匹配角度推出来 |
| 锁 | 行锁、间隙锁、next-key lock 分别锁住什么? | 能结合具体 SQL 说出加锁范围 |
| 日志 | redo log、undo log、binlog 各自解决什么问题? | 能说出刷盘时机和两阶段提交 |
| MVCC | 版本链和 ReadView 怎么配合实现快照读? | 能画出流程,能区分 RC 和 RR |
这个清单是我今天最重要的骨架。接下来所有背诵内容,全部往这五个模块里填。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 事务、锁、日志加隔离级别:用一条逻辑链串起MySQL核心
2.1 事务ACID,别从定义背起
以前我背 ACID,张嘴就是“原子性、一致性、隔离性、持久性”,面试官如果追问“怎么保证的”,我就卡住。今天换了个方向,从一个场景开始推:你给朋友转一百块钱,扣款成功,但入账失败,系统还崩溃了。这时候你希望数据库做什么?答案是:要么两边都成功,要么两边都失败,不能出现中间状态。这就是原子性。
再想深一层,原子性靠什么保证?靠 undo log。事务执行过程中,如果需要回滚,InnoDB 会根据 undo log 里的旧值把数据恢复回去。那持久性呢?靠 redo log,只要事务提交时 redo log 写成功了,就算内存脏页还没落盘,崩溃后也能通过重放日志恢复。隔离性则靠锁和 MVCC。最后一致性其实是目标,前面三个机制加上数据库约束,共同保证数据从一个一致状态变到另一个一致状态。
这个“目标-手段”的关系,比单纯背四个名词管用得多。面试官问到“ACID 分别由什么实现”,你可以很快从转账场景推出来,而不是回忆原话。
2.2 隔离级别和MVCC的关系
隔离级别是接着事务讲的。四个级别从宽松到严格依次是:读未提交、读已提交、可重复读、串行化。它们分别解决脏读、不可重复读、幻读。MySQL InnoDB 默认是“可重复读(REPEATABLE READ)”,这和其他数据库默认“读已提交”不太一样,是一个高频考点。
很多人记不住这三个问题,我找到一个顺口的场景。脏读就是事务 A 读了事务 B 还没提交的修改,结果 B 回滚了,A 读到的是不存在的“脏数据”。不可重复读是同一个事务里,第一次读 id=1 是 100,第二次读变成 50,因为别的事务提交了更新。幻读更诡异,同一个事务里,第一次 select 出 5 行,第二次 select 出 6 行,多出来的那行像幻觉一样。
MySQL 在“可重复读”级别下,用 MVCC 解决了普通快照读的幻读问题。什么是 MVCC?简单说就是多版本并发控制,每一行数据不只有一个版本,修改数据时旧版本不会立即消失,而是通过 undo log 维护一条版本链。事务读取时,借助 ReadView 决定能看到哪个版本。但在“当前读”场景下,比如 select ... for update 或者 update 语句,光靠 MVCC 不够,还要配合 next-key lock 才能锁住范围,避免幻读。这就是隔离级别和锁、MVCC 三者最核心的交汇点。
2.3 锁的细节:从表锁到next-key lock
锁这块,我前三天背得最痛苦,因为概念太多。今天把它拆成粒度、类型、场景三层。
粒度上,InnoDB 支持表锁和行锁。行锁是依靠索引实现的,如果更新条件没有索引,InnoDB 没法定位到具体行,只能锁定整张表,这也是为什么“where 条件没索引会导致锁表”。从面试角度,你要能说出:行锁锁的是索引记录,而不是单纯的行数据。
类型上,最基础的是共享锁(S锁)和排他锁(X锁)。加锁范围再细分,有记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-Key Lock)。记录锁锁住一条记录;间隙锁锁住两个索引记录之间的区间,目的是防止幻读;临键锁是记录锁和间隙锁的组合,锁住一个左开右闭的区间。举个例子,如果 id 索引有 1、4、7 三条记录,在 RR 级别下执行 select * from t where id = 4 for update,如果 4 是普通索引列而非唯一索引,InnoDB 不仅锁 id=4 这条记录,还可能在 id 范围 (1,4] 和 [4,7) 上加上临键锁,具体范围要看索引情况和查询条件。
死锁也是高频题。死锁就是两个事务互相持有对方需要的资源,比如事务 A 先更新 id=1 再更新 id=2,事务 B 先更新 id=2 再更新 id=1,两边都不放手。MySQL 会检测死锁并回滚代价较小的事务。日常避免死锁的方法就三条:保持多个事务访问资源的顺序一致;尽量缩短事务执行时间;让 SQL 尽可能走索引,减少锁范围。
2.4 redo/undo/binlog是干什么的
日志是三座大山,我之前经常混。今天用一句大白话给它们定性:redo log 是“记录改了什么”,undo log 是“记录原来是什么”,binlog 是“记录这条变更长什么样”。注意 binlog 和 redo/undo 还不在一层,redo 和 undo 是 InnoDB 存储引擎层的日志,binlog 是 MySQL Server 层的日志。
redo log 使用的是 WAL(Write-Ahead Logging)机制,也就是先写日志,再写磁盘。为什么要这样做?因为磁盘随机写很慢,而 redo log 是顺序追加写,性能高。InnoDB 把数据页先更新到内存里的 Buffer Pool,同时把这次修改顺序写到 redo log buffer,等 commit 的时候再按参数策略刷入磁盘。这就是为什么“提交了就基本不会丢数据”,因为哪怕内存脏页丢了,redo log 还在,服务重启后可以重放。
undo log 除了用于事务回滚,还负责支撑 MVCC 的版本链。事务回滚时,InnoDB 拿着 undo log 里的旧值覆盖回去;MVCC 读取时,也通过 undo log 找到历史版本。binlog 则用来做主从复制,主库把 binlog 发给从库,从库重放 binlog 保持数据一致。两类日志最麻烦的问题就是如果都写了,但一个成功一个失败,数据会乱。于是 MySQL 用了两阶段提交把 redo log 和 binlog 绑定在一起,这个我在下一节结合 update 语句细讲。
3. 一条UPDATE语句的完整旅程:把八股从“背”变成“推”
3.1 语句执行前:连接器、分析器、优化器
MySQL 接收一条 SQL,不止是直接改数据。你可以把一条 update t set name='小明' where id=1 的完整过程当成一条流水线,八个环节缺一不可。第一个是连接器,负责校验账号和权限,拿到一个连接。第二个是分析器,做词法分析和语法分析,看看这条 SQL 写没写错,表名、字段名存不存在。第三个是优化器,这一步很容易被忽略,却直接关系到性能。比如一条 SQL 可能有多个索引可用,优化器要决定用哪个索引、关联顺序怎么排,最终生成执行计划。
面试中常说的“明明建了索引却没用上”,很多问题就出在优化器或者执行阶段。比如对索引列做了函数运算 where YEAR(create_time) = 2025,索引就会失效;或者隐式类型转换,where mobile = 138xxxx 而 mobile 是 varchar,也可能被优化器放弃索引。这些不是背一条“索引失效场景列表”就能完全理解的,最好结合 B+ 树的结构去推:索引列的值在树里已经排好序,一旦你在列上做运算,原顺序就被破坏了,精确定位的优势当然不复存在。
3.2 更新过程中:Buffer Pool、redo log、undo log
执行器拿到执行计划后,开始调用 InnoDB 的接口。假设 id=1 这条记录之前不在 Buffer Pool 里,InnoDB 会先从磁盘把包含这条记录的整页加载到 Buffer Pool。这解释了一个常见面试题:“为什么更新一条数据那么快?因为可能根本没刷磁盘”。数据页落在内存后,要更新这一行,InnoDB 会先给这行记录加排他锁,然后做修改。
重点来了:修改动作发生之前,InnoDB 先把修改前的那行数据写入 undo log。这样一旦事务回滚,能恢复原值;同时这个旧版本也作为版本链前端,供 MVCC 使用。接下来更新 Buffer Pool 里对应数据页,把 name 字段改成新值。这时候内存里的数据和磁盘上的旧数据已经不一致,这块内存页被称为“脏页”。脏页不会立刻写回磁盘,而是等待合适的时机,比如后台线程刷盘或者 Buffer Pool 空间不够时。为了不丢数据,InnoDB 会把本次更新记录到 redo log buffer。事务提交时,根据参数 innodb_flush_log_at_trx_commit 的配置,把 redo log 刷入磁盘。参数为 1 时每次提交都刷盘,最安全但性能稍低;为 0 时每秒刷一次,可能丢一秒日志;为 2 时写到操作系统缓存,由 OS 决定何时落盘。
3.3 提交阶段:两阶段提交为什么这么设计
如果只有 redo log,崩溃恢复其实已经够了。但 MySQL 还有 binlog 要写,而且 binlog 是主从复制的基础,必须保证主库崩溃后,redo log 和 binlog 描述同一次事务是一致的。假设没有两阶段提交,可能出现这种情况:redo log 写成功、binlog 没写成功,主库重启后数据是自己一致的,但从库收不到这条更新的 binlog,主从数据就对不上了。反过来,binlog 写成功、redo log 没写成功,会导致从库多执行一次变更。
所以 InnoDB 把 redo log 的写入拆成两个阶段。事务提交时先写 redo log,状态标记为 prepare,然后写 binlog,最后再把 redo log 状态改为 commit。如果崩溃发生在 prepare 之后、commit 之前,重启后 InnoDB 会检查 binlog 是否完整写入。如果 binlog 完整,就回放 binlog 并提交事务;如果 binlog 不完整,就回滚事务。这套机制把“两个日志的一致性”问题解决了。
3.4 推导一个面试连环问
把这条链路理顺后,我试着推了一个连环问,效果比死记强很多。面试官问:“一条 update 语句的整个过程是什么?”我不能只说“连接器-分析器-优化器-执行器”,还要补上 InnoDB 内部细节。完整回答应该是:MySQL 先通过连接器校验权限,分析器检查语法,优化器决定执行计划,执行器调用 InnoDB 接口;InnoDB 判断记录是否在 Buffer Pool,不在则从磁盘读取;加锁,写 undo log 记录旧值;更新内存数据页;写 redo log buffer,状态 prepare;写 binlog;提交,redo log 状态改 commit;最后脏页由后台线程慢慢刷回磁盘。
面试官大概率会继续问:“如果刚写完 redo log,没写 binlog 就宕机了,怎么办?”根据两阶段提交,重启后 InnoDB 发现 redo log 处于 prepare 状态,binlog 里没有对应事务,于是回滚。再追问:“如果 binlog 写完了,redo log 的 commit 还没写呢?”此时 binlog 完整,MySQL 会认为事务可以提交,重新补 commit,保证主从一致。把这几个场景在脑内过一遍,比背十遍“两阶段提交的四个字”都管用。
4. “堆一题”实战:LeetCode 215 第K大元素,三种解法一次讲透
4.1 题目和面试考点
MySQL 复习到中间,我换了个脑子刷一道堆的算法题,毕竟“堆”本身也是八股里的高频考点。题目是 LeetCode 215,数组中的第 K 个最大元素:给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。注意这里不是第 k 个不同的元素,而是排序后从大到小数第 k 个位置的元素。
这道题为什么是实习面试的常客?因为它能一次性考察排序、堆、分治、复杂度分析四块内容。最暴力的方法是直接排序,时间复杂度 O(n log n),但不是最优。优秀解法常见两条路:一是维护一个大小为 k 的小顶堆,时间复杂度 O(n log k);二是快速选择 QuickSelect,期望时间复杂度 O(n)。面试时最好两种都能写出来,尤其是堆的写法,代码短、思路清晰,很多面试官就爱听。
4.2 小顶堆解法:代码与手推过程
核心思路是只保留当前遍历过元素里最大的 k 个,堆顶是这 k 个元素中最小的那个。等整个数组遍历完,堆顶就是全局第 k 大的元素。有人会困惑:为什么求“第 k 大”要用小顶堆,而不是大顶堆?因为小顶堆的堆顶是堆内最小值,方便淘汰候选者。如果维护大顶堆,堆顶是最大值,你没法判断新元素要不要挤掉谁。小顶堆像是一个“守门员”,每次只把最小候选者换出去,最后留下最大的 k 个。
Python 实现非常简洁:
python复制import heapq
def find_kth_largest(nums, k):
heap = []
for x in nums:
if len(heap) < k:
heapq.heappush(heap, x)
elif x > heap[0]:
heapq.heapreplace(heap, x)
return heap[0]
手动推一遍:nums = [3,2,1,5,6,4],k=2。遍历 3,堆为 [3];遍历 2,堆为 [2,3];遍历 1,小于堆顶 2,跳过;遍历 5,大于堆顶 2,替换,堆为 [3,5];遍历 6,大于堆顶 3,替换,堆为 [5,6];遍历 4,小于堆顶 5,跳过。最后堆顶是 5,正确答案。注意堆内部结构并不是有序数组,但堆顶一定是最小值。
复杂度上,每个元素最多做一次入堆和出堆操作,堆大小为 k,所以单次操作是 O(log k),总时间复杂度 O(n log k),空间复杂度 O(k)。如果 k 远小于 n,这比全排序快很多,而且非常适合海量数据场景,因为你不必把所有数据读进内存。
4.3 快速选择解法:为什么在实习面试中加分
如果面试官追问“能不能做到 O(n)”,你就该抛出快速选择了。快速选择是快速排序的变体:随机选一个基准元素,把数组按“大于基准”和“小于基准”分成两半。如果基准最终落到的位置正好是 k-1,直接返回;如果 k-1 在基准左边,就只递归左边;如果 k-1 在右边,就只递归右边。它不用像快排那样两边都排,所以平均复杂度是 O(n)。
python复制import random
def find_kth_largest(nums, k):
def partition(left, right, pivot_index):
pivot = nums[pivot_index]
nums[pivot_index], nums[right] = nums[right], nums[pivot_index]
store = left
for i in range(left, right):
if nums[i] > pivot:
nums[store], nums[i] = nums[i], nums[store]
store += 1
nums[right], nums[store] = nums[store], nums[right]
return store
def quick_select(left, right):
pivot_index = random.randint(left, right)
pos = partition(left, right, pivot_index)
if pos == k - 1:
return nums[pos]
elif pos < k - 1:
return quick_select(pos + 1, right)
else:
return quick_select(left, pos - 1)
return quick_select(0, len(nums) - 1)
这里我用了降序分区,把大于 pivot 的元素放到左边。partition 里 store 指针负责记录“大于 pivot 的区间边界”,遍历完再把 pivot 放到 store 位置。注意如果选的 pivot 运气不好,可能每次只排除一个元素,最坏复杂度 O(n^2),所以代码里用 random.randint 随机化,让期望复杂度接近 O(n)。面试时如果能说出“随机化是为了防止有序数组导致最坏情况”,很加分。
4.4 面试官追问:海量TopK和MySQL order by有什么关系
这道题做完,面试官经常顺势问一个扩展:如果数据量特别大,比如上亿条记录,内存放不下,找第 k 大怎么办?前面的小顶堆解法已经很适合了,因为只需要维护 k 个元素的内存。如果 k 也大到没法放内存,可以分桶:先对数据按范围粗分桶,统计每个桶的数量,定位第 k 大落在哪个桶,再在桶内用堆或快速选择细找。这本质上就是“分治 + 堆”的组合。
更有意思的是,它和 MySQL 里的 order by ... limit k 是同一个问题。MySQL 做排序时,如果数据量不大,会在内存中使用 filesort,排序算法可能是快速排序或堆排序;如果 order by col limit k 且 k 比较小,优先队列(堆)排序的优势就很明显。如果查询能用上联合索引,MySQL 甚至会直接按索引顺序扫描并取前 k 条,完全省掉排序步骤。这个点和今天背的索引知识完美对上,也算八股和算法题的一次交叉训练。
5. 把知识焊进脑子:间隔重复、费曼式自问自答和二十道自测题
5.1 我为什么放弃抄笔记
前三天我抄了大量笔记,手很累,但脑子没怎么动。今天改用“默写”代替“摘抄”。具体做法是:先看一遍知识点,合上笔记,在纸上画出“一条 update 语句的流程图”,从连接器一直画到 redo log 和 binlog。画完之后和原图对比,哪里缺了就重点标记。这个过程看着慢,实际效率很高,因为每一次默写都是一次提取练习,而提取练习才是形成长期记忆的关键。抄笔记只是重复输入,不产生提取动作,记忆效果自然差。
5.2 把八股改写成面试官逼问脚本
我试过最爽的方法是把知识点编成“面试官连环问”的对话。比如我自己写了一个脚本:
- 面试官:你说说 MySQL 怎么解决幻读?
- 我:在 RR 级别下,MVCC 负责快照读,next-key lock 负责当前读。
- 面试官:那
select * from t where id = 10 for update,如果 id=10 不存在,锁了什么? - 我:如果 id 是普通索引且 10 在某个间隙里,InnoDB 会加间隙锁,锁住 (上一个值, 下一个值) 的开区间,防止其他事务在这个间隙插入。
这种脚本一旦写出来,你就不是在背答案,而是在模拟面试官怎么追着你打。背八股最怕的是一问一答很顺,但面试官换个场景就懵。脚本能帮你提前补上那些“追问逻辑”。我每天晚上会挑两段脚本读一遍,第二天早上再看能不能脱离脚本回答出来。
5.3 复习节奏表
间隔重复对 MySQL 这种信息密度高的内容特别有效。我给自己定了一个节奏:当天背完,当晚睡前快速过一遍;第二天做一次输出型默写;第四天做一次自测;第七天做一套综合问答;第十五天再回来翻一遍易错点。这个 1/2/4/7/15 的节奏不需要特别复杂的工具,Excel 表格就能搞定。
| 复习时间 | 复习内容 | 方式 |
|---|---|---|
| 当天晚上 | 今天画的所有流程图 | 合上笔记,口头复述 |
| 第2天 | 事务、锁、日志 | 默写 update 流程 |
| 第4天 | MVCC、索引失效、两阶段提交 | 做自测题 |
| 第7天 | 所有 MySQL 核心 | 编两个面试追问脚本 |
| 第15天 | 错题和模糊点 | 只看错误标记 |
5.4 二十道MySQL自测题
如果你也想检验自己到底记住没有,可以直接拿这二十道题当镜子。我会在复习时合上笔记本,一道一道说答案,说不利索的标记为“待复习”。
- ACID 四个特性分别由什么机制保证?
- MySQL InnoDB 默认隔离级别是什么?
- 脏读、不可重复读、幻读有什么区别?
- B+ 树为什么适合做索引?和红黑树比有什么优势?
- 聚簇索引和二级索引的叶子节点分别存什么?
- 联合索引 (a,b,c),查询
where b=? and c=?为什么可能走不了索引? - 覆盖索引是什么意思?它为什么能避免回表?
- 索引失效的常见场景有哪些?
- 行锁、间隙锁、next-key lock 各锁住什么范围?
- RR 级别下
select ... for update会加哪些锁? - 死锁发生的必要条件是什么?如何避免?
- redo log、undo log、binlog 各自的作用?
- redo log 的 WAL 机制解决了什么问题?
- 两阶段提交为什么要分成 prepare 和 commit?
- MVCC 的版本链是怎么形成的?
- ReadView 在 RC 和 RR 下的生成时机有什么区别?
- 快照读和当前读有什么区别?
count(*)、count(1)、count(字段)有什么区别?- 为什么通常建议 InnoDB 表用自增主键?
order by col limit 10在什么情况下可以避免 filesort?
这二十题不需要一次全答对,但要保证每一题都能说满一分钟。如果只能说几个关键词,说明还没完全内化。
6. 今天踩过的坑:背八股最容易翻车的三个瞬间
6.1 只背结论,被一句“为什么”问倒
今天下午我试着模拟面试,室友问我“间隙锁到底锁的是记录还是间隙”,我第一反应是回答“锁的是间隙”,但当他追问“为什么要有间隙锁”时,我卡住了。后来翻了笔记才想起来,间隙锁存在的核心原因是防止幻读:如果只锁已有记录,另一个事务在间隙里插入新记录,当前事务第二次读就会多出数据。所以间隙锁不是锁一条具体数据,而是锁住“插入动作可能发生的区间”,达到范围加锁的效果。
这个坑提醒我:背锁的类型时,必须把每个锁和它要解决的问题绑定。记录锁解决的是并发修改同一行的问题,间隙锁解决的是幻读,next-key lock 则是记录锁加间隙锁,在 RR 隔离级别下默认使用。以后我复习任何“是什么”的知识点,都要多问一句“它为了解决什么问题而存在”。
6.2 背书式回答,没有自己的话
另一个问题是我背得太书面化。比如“MVCC 是多版本并发控制”,这句话背得很熟,但让我用自己的话解释“版本链怎么形成”,就变成了一堆术语堆砌。后来我换了个类比:undo log 就像一条时光隧道,每一个旧版本都是隧道路上的站点。事务每修改一次记录,旧值就被压到版本链头部,新值留在当前。ReadView 是通行证,上面记录了当前哪些事务还没提交,读到版本时先看这个版本的“事务ID”在不在通行证的黑名单里,在就不能读,要继续往前翻。
这个说法不是标准定义,但面试官听了会觉得你确实理解。八股背诵最终要转化成自己的语言,而不是当复读机。今天最大的收获就是:把每个知识点都翻译成“我自己的话”以后,遗忘速度明显下降。
6.3 浪费时间死磕冷门知识点
今天我还踩了一个效率陷阱:在“MySQL 安装配置”和“mysql 中 int+5”这类边角料上花了不少时间。对于准备实习面试来说,核心机制远比安装细节重要。安装 MySQL 可以下载官方安装包一路下一步,但面试不会问“你怎么配置 my.ini”。所以我想提醒同样在准备实习的朋友,复习优先级应该是:事务和隔离级别 > 索引与优化 > 锁 > 日志与 MVCC > 常见 SQL 写法 > 安装和工具使用。前四项是面试重灾区,后两项是工作中慢慢积累的,别让安装教程占掉你背八股的黄金时间。
最后分享一个我今晚刚验证过的小技巧:把“一条 UPDATE 语句的完整旅程”用手机录音讲了一遍,录到一半卡壳,往回翻笔记再讲,最后录音从三分钟变成八分钟。这个过程比抄一遍笔记有用太多,因为它逼着你把脑子里的知识重新组织一遍,组织得越顺畅,记得越牢。如果你也正在背八股,别只盯着“记住”两个字,试着当一次老师,讲给自己听。明天第 48 天继续,我打算把 MySQL 锁和索引的底层数据结构串起来重新过一遍。
