社招三年后端开发核心面试题汇总与解析
对于拥有三年经验的后端开发工程师而言,面试不仅考察基础知识的广度,更看重对原理的深入理解及实际场景中的优化能力。本文汇总了高频出现的 20+ 道核心技术问题,涵盖 MySQL、Redis、Java 并发、网络协议、分布式系统及算法等模块,旨在帮助开发者系统梳理知识体系。
一、MySQL 数据库核心考点
1. MySQL 索引在什么情况下会失效
索引失效是性能优化的常见痛点,以下情况需特别注意:
- 查询条件包含 OR:若 OR 两边的字段中至少有一个没有索引,可能导致全表扫描。
- 类型隐式转换:字符串字段查询时未加引号(如
where name = 123),会导致索引失效。 - 模糊查询前缀通配符:使用
LIKE '%abc'无法利用索引,而LIKE 'abc%'可以。 - 联合索引顺序:违反最左前缀原则,查询条件未包含联合索引的第一个列。
- 函数运算:在索引列上使用内置函数或表达式(如
WHERE YEAR(create_time) = 2023)。 - 范围查询后的列:联合索引中,范围查询(>、<)之后的列索引失效。
- 否定查询:使用
!=、<>、NOT IN可能触发全表扫描。 - IS NULL/IS NOT NULL:在某些版本或特定统计信息下可能导致索引失效。
- 字符集不一致:关联字段编码格式不同(如 utf8mb4 vs latin1)。
- 优化器选择:当优化器估算全表扫描成本低于走索引时,将放弃索引。
2. InnoDB 与 MyISAM 存储引擎的区别
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务支持 | 支持 (ACID) | 不支持 |
| 外键 | 支持 | 不支持 |
| 锁粒度 | 行级锁 / 表级锁 | 仅表级锁 |
| MVCC | 支持 | 不支持 |
| 全文索引 | 5.7+ 支持 | 原生支持 |
| 计数速度 | COUNT(*) 需扫描 | 有内部计数器,速度快 |
| 崩溃恢复 | 支持崩溃安全恢复 | 易损坏,需修复 |
| 主键要求 | 必须有主键 | 可选 |
InnoDB 更适合高并发写操作及需要事务保障的场景;MyISAM 适合读多写少且无需事务的场景。
3. MySQL 项目中的优化场景与慢查询解决
面对慢查询,标准排查流程如下:
- 开启慢查询日志 (
slow_query_log),定位耗时 SQL。 - 使用 EXPLAIN 分析执行计划:关注
type(是否全表扫描)、key(实际使用的索引)、rows(扫描行数)。 - 优化 SQL 语句:避免
SELECT *,优化JOIN连接顺序,调整GROUP BY和ORDER BY策略。 - 索引优化:根据执行计划添加覆盖索引或联合索引。
- 架构层面:数据量过大时考虑分库分表、读写分离或引入缓存。
4. MySQL 索引模型
常见的索引数据结构包括 B+ 树、Hash 等。MySQL InnoDB 默认使用 B+ 树索引。B+ 树非叶子节点仅存储索引键,叶子节点存储数据并双向链接,适合范围查询和排序。
5. B-树与 B+ 树的区别?为什么不用红黑树
- 区别:
- B-树节点同时存储键和数据;B+ 树非叶子节点仅存键,数据仅在叶子节点。
- B+ 树叶子节点通过链表连接,支持高效范围遍历。
- B+ 树层级更低,IO 次数更少。
- 为何不用红黑树:红黑树高度较高,磁盘 IO 次数多;且红黑树插入删除旋转复杂,维护成本高。
- 为何不用 Hash:Hash 仅支持等值查询,不支持范围查询和排序。
6. MySQL 主从同步原理
主从复制基于 Binlog 实现,主要步骤:
- Master 写入 Binlog:更新操作记录到二进制日志。
- Slave 连接 Master:发起 I/O 线程连接请求。
- Binlog Dump:Master 创建线程将 Binlog 发送给 Slave。
- 中继日志:Slave 的 I/O 线程接收 Binlog 写入 Relay Log。
- SQL 重放:Slave 的 SQL 线程读取 Relay Log 并重放执行。
高可用方案:MHA、Orchestrator 或 MGR 集群。
7. 乐观锁与悲观锁的区别
- 悲观锁:假设冲突概率高,操作前先加锁(如
SELECT ... FOR UPDATE)。适用于写多读少场景,但并发度低。 - 乐观锁:假设冲突概率低,不加锁,更新时检查版本号或时间戳(CAS 机制)。适用于读多写少场景,减少锁竞争。
8. Binlog 日志详解
Binlog 是归档日志,用于主从复制和数据恢复。三种格式:
- Statement:记录 SQL 原文。节省空间,但可能因索引差异导致主从不一致。
- Row:记录行变更数据。一致性高,但文件体积大。
- Mixed:混合模式,自动选择 Statement 或 Row。
二、Redis 缓存核心考点
9. Redis 持久化方式及选型
- RDB (快照):定时保存内存数据集快照。恢复快,适合备份;缺点是可能丢失最后一次快照后的数据。
- AOF (追加日志):记录每次写命令。数据安全性高,支持秒级恢复;缺点是文件大,恢复慢。
- 混合持久化:Redis 4.0+ 支持,结合 RDB 快速加载与 AOF 高可靠性。
- 选型建议:生产环境推荐混合持久化;纯缓存场景可只用 RDB。
10. Redis 主从同步过程
- 连接协商:Slave 发送
PSYNC命令。 - 全量同步:Master 执行
BGSAVE生成 RDB 发给 Slave,Slave 清空加载。 - 增量同步:Master 将全量期间的新写命令发送至 Slave 的复制缓冲区,Slave 重放。
11. Redis ZSet 实现原理
ZSet 底层采用 压缩列表 (ziplist) 或 跳跃表 (skiplist)。
- 小数据量:成员数 < 128 且长度 < 64 字节时使用 ziplist,节省内存。
- 大数据量:使用 skiplist,支持 O(logN) 的插入、删除、查找,适合排行榜场景。
12. Redis 过期与淘汰策略
- 过期策略:
- 定时过期:精确但 CPU 消耗大。
- 惰性过期:访问时检查,节省 CPU 但内存占用高。
- 定期过期:随机抽样检查,平衡 CPU 与内存。
- 内存淘汰:
volatile-lru:已过期键中 LRU 淘汰。allkeys-lru:所有键中 LRU 淘汰。noeviction:不淘汰,写入报错。- 其他还包括 LFU、Random、TTL 等策略。
三、Java 基础与并发
13. HashMap 实现原理
- JDK 1.7:数组 + 链表。头插法扩容。
- JDK 1.8:数组 + 链表 + 红黑树。尾插法扩容,链表转树阈值 8。
- 为何转红黑树:链表过长(>8)时查找退化为 O(N),红黑树保证 O(logN)。
- 线程安全:HashMap 非线程安全。多线程扩容可能死循环(1.7)或数据覆盖(1.8)。建议使用
ConcurrentHashMap。
14. Select 与 Epoll 区别
- Select:轮询所有 fd,最大连接数限制(1024),O(n) 复杂度。
- Epoll:事件驱动,回调机制,无连接数限制,O(1) 复杂度。适合高并发场景。
四、网络与分布式系统
15. HTTP 与 HTTPS 区别及加密原理
- 区别:HTTPS = HTTP + SSL/TLS,端口 443,加密传输,证书验证。
- 加密流程:
- 客户端请求,服务器返回证书(含公钥)。
- 客户端验证证书合法性。
- 客户端生成随机对称密钥,用公钥加密后发送。
- 服务器用私钥解密得到对称密钥。
- 后续通信使用对称密钥加密,兼顾效率与安全。
16. Raft 算法原理
Raft 是一种共识算法,包含 Leader、Follower、Candidate 三种角色。
- 选举:超时未收到心跳则转为 Candidate,请求投票,过半数当选 Leader。
- 日志复制:Leader 接收请求,复制日志给 Follower,多数确认提交。
- 一致性:Leader 强制 Follower 同步日志,确保状态机一致。
17. 消息中间件高可用
以 Kafka 为例:
- 副本机制:Partition 数据同步到多个 Broker,形成 Leader/Follower 副本。
- 故障转移:Leader 宕机后,Follower 重新选举新 Leader,保证服务不中断。
18. 消息队列不丢消息保障
- 生产者:同步发送 + 重试机制,或使用事务消息。
- Broker:同步刷盘 + 同步复制(Master-Slave 均写入成功才 ACK)。
- 消费者:手动 ACK,业务逻辑执行成功后再确认消费。
19. Redis 哨兵机制
Sentinel 集群监控主从节点:
- 主观下线:单个哨兵认为 Master 不可用。
- 客观下线:多数哨兵确认 Master 不可用。
- 故障转移:选举新 Master,通知 Slave 切换,更新配置。
五、算法实战
20. 无重复字符的最长子串
题目:给定字符串 s,找出其中不含有重复字符的最长子串的长度。 思路:滑动窗口 + 哈希集合。 代码实现:
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
Set<Character> window = new HashSet<>();
int left = 0, right = 0;
int res = 0;
while (right < s.length()) {
char c = s.charAt(right);
while (window.contains(c)) {
window.remove(s.charAt(left));
left++;
}
window.add(c);
res = Math.max(res, window.size());
right++;
}
return res;
}
该解法时间复杂度为 O(N),空间复杂度为 O(min(M, N)),其中 M 为字符集大小。
结语
以上知识点覆盖了后端开发面试的核心领域。建议在实际工作中结合业务场景加深理解,不仅要知其然,更要知其所以然。持续积累技术深度,才能在职业发展中保持竞争力。

