期末周复习到崩溃:数据库事务、栈专题,还有没看懂的 RAG 项目
期末周复习到崩溃:数据库事务、栈专题,还有没看懂的 RAG 项目
前言
大家好,我是瓦瓦gogo,这是这两天的学习复盘。
这两天明显进入期末周节奏了,整个人的时间被学校考试切得很碎。好消息是学校书本上的数据库内容终于复习完了;坏消息是数值计算刚开始复习,就已经感觉有点痛苦了。公式、误差、迭代这些东西看起来都不算特别长,但真要自己算、自己理解,还是挺折磨的。
原本还想着这几天抽时间看看之前项目,尤其是简历上写过的 RAG 项目和之前公司的业务代码,结果现实是:期末一来,项目基本没时间碰。现在只能先保证学校考试不掉链子,再尽量每天挤一点时间补面试八股和算法。
数据库书本内容复习完了
这两天学校数据库这块主要是在按书本复习。相比面试八股,书本内容更偏系统一些,比如关系模型、SQL、关系代数、数据库设计、范式、事务这些。以前学的时候感觉知识点很多很散,这次复习完之后,至少对数据库这门课的整体结构清楚了一点。
我现在的感觉是,学校考试和面试复习关注点不太一样。考试更容易考概念、计算、SQL 写法和规范化分析;面试更喜欢问实际开发中会遇到的问题,比如事务为什么会出问题、隔离级别怎么选、索引为什么失效、慢 SQL 怎么排查。
所以复习书本的时候,我也顺便把数据库事务和隔离机制当成八股重新过了一遍。
数据库事务和隔离机制
事务这块最基础的是 ACID:
- 原子性:事务里的操作要么全部成功,要么全部失败
- 一致性:事务执行前后,数据库要保持合法状态
- 隔离性:多个事务并发执行时,彼此之间不能随便干扰
- 持久性:事务提交之后,结果要持久保存
面试里一般不会只问 ACID 是什么,更容易继续问并发事务会产生哪些问题。这里主要有三个:
- 脏读:一个事务读到了另一个事务还没提交的数据
- 不可重复读:同一个事务里两次读取同一行数据,结果不一样
- 幻读:同一个事务里两次按条件查询,结果集数量变了
然后就是四种隔离级别:
- 读未提交:可能出现脏读、不可重复读、幻读
- 读已提交:解决脏读,但可能出现不可重复读和幻读
- 可重复读:解决脏读和不可重复读,MySQL InnoDB 默认是这个级别
- 串行化:隔离最强,但并发性能最差
我觉得这里最容易混的是不可重复读和幻读。不可重复读更偏向同一行数据被修改了,比如第一次查余额是 100,第二次变成 80。幻读更偏向结果集变化,比如第一次查符合条件的记录有 3 条,第二次变成 4 条。
这块后面还得继续结合 MVCC、undo log、read view 去理解,不然只背隔离级别还是有点虚。
算法:开始做栈专题
算法这两天开始做栈专题,刷了三道比较基础但很经典的题:用栈模拟队列、用队列模拟栈、判断括号是否合法。
这几题看起来简单,但我感觉它们适合用来重新理解数据结构的特性:栈是后进先出,队列是先进先出。题目本质上就是让我们用一种结构模拟另一种结构。
用栈模拟队列
这题的思路是准备两个栈:一个输入栈,一个输出栈。入队时直接放到输入栈;出队时如果输出栈为空,就把输入栈里的元素全部倒过去。
class MyQueue {
private Deque<Integer> in = new ArrayDeque<>();
private Deque<Integer> out = new ArrayDeque<>();
public void push(int x) {
in.push(x);
}
public int pop() {
move();
return out.pop();
}
public int peek() {
move();
return out.peek();
}
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
private void move() {
if (out.isEmpty()) {
while (!in.isEmpty()) {
out.push(in.pop());
}
}
}
}
关键点是只有 out 为空时才倒数据,不是每次 pop 都倒。这样可以避免重复搬运元素,整体效率更好。
用队列模拟栈
用队列模拟栈可以用一个队列完成。每次新元素入队之后,把前面的旧元素依次移到队尾,这样队头永远是最后入栈的元素。
class MyStack {
private Queue<Integer> queue = new LinkedList<>();
public void push(int x) {
queue.offer(x);
int size = queue.size();
for (int i = 0; i < size - 1; i++) {
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
这题让我理解到,模拟数据结构不是死记写法,而是要想办法维护目标结构的访问顺序。栈要后进先出,所以每次 push 后都把新元素转到队头。
判断括号是否合法
括号匹配是栈最经典的应用。遇到左括号就入栈,遇到右括号就看栈顶是不是对应的左括号。
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(') {
stack.push(')');
} else if (c == '[') {
stack.push(']');
} else if (c == '{') {
stack.push('}');
} else if (stack.isEmpty() || stack.pop() != c) {
return false;
}
}
return stack.isEmpty();
}
这里我觉得比较巧的写法是:遇到左括号时,不是把左括号本身入栈,而是把它期待匹配的右括号入栈。这样遇到右括号时,只需要判断当前字符和栈顶是否相等,代码会更简洁。
RAG 项目到底应该怎么学
这两天还有一个很现实的问题:简历上以前写过 RAG 项目,但现在回头看,其实很多地方没有真正弄懂。
当时更多是跟着教程跑起来,知道大概是文档切分、向量化、存到向量库、检索、再把结果交给大模型回答。但如果面试官继续问,比如为什么要切 chunk、chunk 多大合适、召回结果怎么排序、为什么会答非所问、怎么评估效果,我可能就不太能讲清楚。
所以现在有点想求教一下:学项目到底应该怎么学?尤其是 RAG 这种项目,是不是不能只停留在“我把项目跑起来了”,而是应该按链路拆开:
- 数据怎么进来
- 文档怎么切分
- embedding 怎么生成
- 向量库怎么存和查
- 检索结果怎么过滤和排序
- prompt 怎么拼接
- 回答效果怎么评估
- 出问题时怎么定位
我现在打算等 7 月 2 号期末考完之后,7 月中继续投简历,看看能不能找一份大一点公司的日常实习。在这之前,项目这块必须重新补,不然简历上写了但讲不清,面试反而会变成扣分项。
今日总结
这两天整体就是期末周夹着面试准备一起往前走。数据库书本内容复习完了,顺便过了一遍事务和隔离级别;算法开始做栈专题,三道题都比较基础,但能帮我重新理解栈和队列的特性;数值计算刚开始复习,确实有点难。
现在比较焦虑的是项目没时间看,尤其是 RAG 项目之前没有真正吃透。后面如果还有时间,我想把项目按“链路、核心问题、可优化点、面试怎么讲”重新整理一遍。期末周先活下来,项目和简历等考试结束后再集中补。
为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。
更多推荐



所有评论(0)