你好,我是Sia。
上周,我终于收到了那个等了很久的 offer。
你可能觉得没什么了不起。但对我来说,这背后是两个月的煎熬、十几次的拒绝,以及无数次深夜的自我怀疑。
我从一所普通二本毕业,在一家小公司做了两年 Java 开发。平时写写 CRUD,改改 bug,日子过得还算安稳。直到今年开始投简历,我才发现 ——外面的世界和我想的完全不一样。
第一次面试,面试官问我:“你们项目怎么做接口幂等的?”
我愣住了。幂等?好像听过,但从没真正实现过。
第二次面试,面试官问:“你们的 QPS 大概多少?有没有做过压测?”
我说了个数,面试官笑了一下,没说话。那个笑容我现在还记得。
第三次、第四次…… 连续被拒。
直到上周这家公司给了我 offer,面试官最后说了一句话:“基础不错,能看出来你最近在认真补课。”
我想把这段经历里,我最痛的几个 “坑” 分享给你。希望你能绕过它们。
一、自我介绍:别把简历背一遍
前几次面试,我的自我介绍是这样的:
“我叫阿尘,毕业于 XX 学院,有 2 年 Java 经验,做过电商后台和 OA 系统,熟悉 Spring Boot、MyBatis、Redis……”
面试官听完,低头看简历,然后问:“你说说你们电商项目的亮点?”
我:……
后来我才明白:自我介绍是你唯一能主动 “画重点” 的机会。
我改成了这样:
“面试官您好,我有 2 年 Java 经验。我工作中最擅长的两件事:一是排查线上问题,二是做性能优化。
比如我们之前有个报表导出功能,10 万行数据就 OOM 了。我用了 EasyExcel 的流式处理,内存占用从 800MB 降到了 50MB。
再比如,我们有个订单查询接口很慢,我通过分析慢查询日志、加联合索引、调整 SQL,把响应时间从 2 秒优化到了 100 毫秒以内。
我主要想跟您聊聊我在性能优化和 Redis 实战上的经验。”
效果完全不同。 面试官立刻来了兴趣:“那个 OOM 问题,你具体是怎么排查的?”
你看,自我介绍的核心不是 “你做过什么”,而是 “你能解决什么问题”。
二、索引:我踩过最深的坑
面试官问:“你们项目中索引是怎么用的?”
这个问题我答过很多次。但有一次,面试官追问了一句,让我后背发凉:
“你实际工作中,有没有建了索引但没走的情况?”
我沉默了。
后来我把这个问题彻底研究了一遍,现在可以很自信地回答:
常见原因有以下几种:
- 在索引列上做了计算或函数
-- ❌ 不走索引
SELECT * FROM user WHERE age + 1 = 20
-- ✅ 走索引
SELECT * FROM user WHERE age = 19
- 隐式类型转换
-- 假设id是int类型
-- ❌ 不走索引(数字字段传字符串)
SELECT * FROM user WHERE id = '123'
-- ✅ 走索引
SELECT * FROM user WHERE id = 123
- LIKE 以 % 开头
-- ❌ 不走索引
SELECT * FROM user WHERE name LIKE '%张三%'
-- ✅ 走索引(仅前缀匹配)
SELECT * FROM user WHERE name LIKE '张三%'
- 联合索引没有遵循最左前缀法则
-- 联合索引 (a, b, c)
-- ✅ 走索引
WHERE a = 1 AND b = 2
-- ❌ 不走索引(跳过了a)
WHERE b = 2 AND c = 3
我亲身踩过的坑:把索引顺序建反了,导致一条 SQL 跑了 2 秒,调整顺序后 20 毫秒。建索引不是越多越好,而是要建在刀刃上。
三、缓存穿透 / 击穿 / 雪崩:面试必考三兄弟
这三个概念,我背了无数遍。但有一次面试官说:“你别背定义,就说你项目里怎么用的。”
我又卡住了。
现在的我,可以这样回答:
缓存穿透(查不到的数据)
场景:有人恶意请求id = -1的数据,每次都会打到数据库。
解决方案:
// 查询不到时,缓存一个空对象,过期时间短一些
if (dbResult == null) {
redis.setex(key, 60, "null"); // 缓存60秒
return null;
}
缓存击穿(热点数据过期)
场景:一个爆款商品的缓存刚好过期,瞬间大量请求打到数据库。
解决方案:互斥锁,只让一个线程去查数据库。
String lockKey = "lock:" + key;
Boolean locked = redis.setnx(lockKey, "1", 10);
if (locked) {
try {
// 双检:再查一次缓存
data = redis.get(key);
if (data != null) return data;
// 查数据库 + 写缓存
data = db.query(key);
redis.setex(key, 1800, data);
return data;
} finally {
redis.del(lockKey);
}
} else {
// 短暂等待后循环重试,避免递归栈溢出
Thread.sleep(50);
continue;
}
缓存雪崩(大量 key 同时过期)
解决方案:过期时间加随机值,避免集体过期。
int baseExpire = 1800; // 30分钟
int randomOffset = new Random().nextInt(300); // 0-5分钟随机
int finalExpire = baseExpire + randomOffset;
redis.setex(key, finalExpire, value);
这三个问题,每一个我都实际遇到过。 纸上得来终觉浅,绝知此事要躬行。
四、面试官问:你还有什么想问的?
以前我总说 “没有了谢谢”。后来一个做 HR 的朋友告诉我,这个问题不是走形式,是你的加分题。
我后来会问三个问题:
- “这个岗位进来后主要做什么业务?技术栈上有什么挑战?”
表现认真和兴趣。
2. “如果我有幸入职,您希望我前三个月重点在哪些方面提升?”
表现成长意愿和对 Leader 期待的重视。
3. “团队目前在技术上遇到的最大难点是什么?”
这个问题最加分。面试官跟我聊了十几分钟他们的慢 SQL 治理和分库分表难题。
提问环节是你最后展示自己的机会,别浪费。
最后
这两个月,我被拒绝过,被已读不回过,也被面试官怼过。
但我还是走出来了。
如果你也正在面试的煎熬中,别放弃。被拒不代表你不行,可能只是还没遇到那个匹配的机会.
为了帮助更多像我一样正在面试的朋友,如果你正在备战 Java 后端或者前端或者测试,想要真实的投递渠道,:point_right:** 点击这里进行投递吧**:https://jsj.top/f/o38ijj
完全免费,纯属互助。 希望能帮到每一个还在咬牙坚持的你。
Offer 会来的。相信我。