面灵AI→

28 届两次面试记录:Java 后端项目拷打与一场全栈面试

时间
2026-10
来源
牛客网

《面试题目》

  1. 悦享本地生活服务平台用到限流、秒杀、布隆过滤器,你们的流量、并发大概有多大?
  2. 布隆过滤器是什么作用,原理是什么?
  3. 用户量多大,日活有多少?
  4. SQL 优化这块,是怎么排查数据库问题的?
  5. 索引是什么?
  6. 本地事务和分布式事务分别是什么?
  7. 项目里 Redis 分布式锁解决了什么业务问题?
  8. JWT 权限认证是什么情况?
  9. 拦截器和过滤器的区别?
  10. Redis 里面常用的数据结构都有哪些?
  11. 接口和抽象类,二者有什么区别?
  12. List 和 Set 什么情况下用 List?什么情况下用 Set?

《参考解析》

被追问「流量多大、日活多少」时:答量级和来源,别编精确数字。这类问题面试官真正想验证的是你有没有真的跑过这个系统、有没有量化的概念。可用的答法是把口径说清楚:峰值 QPS 与平均 QPS 分别是多少、用户量是注册还是活跃、数据从哪来(监控面板、压测报告、还是日志统计),然后给出一个区间而不是一个虚假的精确值。如果手上确实没有数据,就明确说「当时没有做完整监控,我只能按压测结果和订单量估算大概在 X 量级」,再补一句「如果重做,我会在入口处埋点统计 QPS 与耗时分布」。进一步的追问通常会落到容量与瓶颈:限流阈值怎么定的、秒杀用了什么手段(前置校验、库存预热到 Redis、异步下单、令牌桶或漏桶)、系统在什么量级会先撑不住(数据库连接池、Redis 单线程、还是网络带宽)。回答里带上「怎么测出来的」和「瓶颈在哪」,比背一串漂亮数字更让人信服。

布隆过滤器:位数组加多个哈希函数,用误判率换空间。原理是把元素经 k 个独立哈希映射到位数组的 k 个位置并置 1;查询时如果有一位是 0,则元素一定不存在;如果全为 1,则可能存在(存在误判)。它的空间效率极高(每个元素约 10 bit 就能把误判率压到 1% 左右),代价是不能删除元素、不支持枚举,且误判率随插入量增长而上升。工程用法是放在缓存前面挡穿透:请求先过布隆过滤器,判定不存在就直接返回,避免无效查询打到数据库;需要删除的场景用计数布隆或定期重建(把新数据写到新过滤器,双写一段时间再切换)。答的时候建议给出参数关系——位数组长度 m、元素个数 n、哈希个数 k 满足 k ≈ (m/n)·ln2 时误判率最低,并指出它和布谷鸟过滤器的区别(后者支持删除),这会把答案从「知道名词」拉到「会调参」。

SQL 优化排查:要按固定顺序走,别一上来就说加索引。完整的排查链路是:先确认慢在哪条语句(慢查询日志、performance_schema、APM 里的 SQL 耗时排行),再看执行计划(EXPLAIN 关注 type 是否全表扫描、key 命中了哪个索引、rows 与 filtered 估算、Extra 里有没有 Using filesort 或 Using temporary),然后判断原因属于哪一类:索引缺失或失效(字段上做函数运算、隐式类型转换、前导模糊匹配、违反最左前缀)、索引选错(区分度太低导致优化器放弃)、回表过多(考虑覆盖索引)、数据量太大(分页深翻页用游标或延迟关联)、还是锁等待与连接池耗尽(这类不是语句问题)。索引的本质是排好序的数据结构(InnoDB 是 B+ 树)加指向数据行的引用,它把随机 IO 变成有序查找,代价是占空间并拖慢写入,所以索引不是越多越好。补充一点高频考点:EXPLAIN 的 type 从好到坏大致是 system > const > eq_ref > ref > range > index > ALL,看到 ALL 基本就是全表扫描。

本地事务与分布式事务:先讲清边界,再讲补偿。本地事务是单个数据库连接内的一组操作,靠 undo/redo log 保证 ACID,Spring 的 @Transactional 在同一个数据源下就能覆盖。分布式事务横跨多个数据库或服务,2PC/XA 强一致但同步阻塞、协调者单点,性能差;TCC 把操作拆成 Try-Confirm-Cancel,需要业务自己写三个接口并且要处理空回滚、悬挂、幂等;本地消息表与事务消息(先写本地事务再发消息,靠定时补偿保证最终一致)是互联网场景最常用的方案;Saga 把长事务拆成一串本地事务并定义补偿动作,适合流程长、可容忍中间态的业务。选型判断就一句话:能不能接受最终一致——能,就优先本地消息表或 Saga,避免为了强一致把吞吐拉垮。Redis 分布式锁则要讲清为什么用它(跨进程互斥,比如防止同一订单被重复处理),以及它的坑:加锁要带唯一 value、解锁要校验 value 并做成原子操作(Lua)、必须有超时兜底、锁过期而业务没跑完时需要看门狗续期,强一致场景应该用 Redlock 之外的方案(如基于数据库或 ZooKeeper)。

Java 基础三连:JWT、拦截器与过滤器、接口与抽象类、List 与 Set。 JWT 是自包含的令牌,由头部、载荷、签名三部分组成,服务端用密钥验签即可解析身份,好处是无状态、跨服务方便,代价是无法主动失效(只能靠短过期时间加刷新令牌或黑名单)、载荷仅做 Base64 编码不能放敏感信息,且要用强密钥并校验算法字段防止算法混淆攻击。拦截器与过滤器分属两层:Filter 是 Servlet 规范的一部分,在请求进入 Servlet 之前生效,能拿到原始 HttpServletRequest,适合做编码、跨域、日志、鉴权粗筛;Interceptor 属于 Spring MVC,能拿到 HandlerMethod,适合做细粒度鉴权、参数校验与统一响应包装,两者的执行顺序是 Filter → Interceptor → Controller。接口与抽象类的区别在于:接口是行为契约,可多实现、只声明(Java 8 起有默认方法与静态方法)、字段隐式 public static final;抽象类是模板,单继承,可有构造器、成员变量与部分实现,适合复用公共逻辑。List 与 Set 的选择看是否需要顺序与重复:List 有序可重复、支持按下标访问(ArrayList 随机访问快,LinkedList 头尾增删快),Set 元素唯一(HashSet 靠哈希去重、无序,LinkedHashSet 保插入序,TreeSet 有序但 O(log n)),去重与判重优先 Set,需要保序与索引就用 List。

复盘建议:简历决定了提问范围,第二场面试要主动控场。第一场问题几乎全从简历上的项目出发,说明面试官是「按你写的挖」,所以简历里出现的每个技术名词都要能讲三层——为什么用、怎么实现的、遇到什么问题怎么处理;写了却讲不清的,反而会成为失分点,不如不写。第二场是线下全栈面,形式更像沟通:自我介绍加 HR 介绍业务后问你的想法,这种场景要提前准备一段一百字左右的自我介绍(专业背景、最有代表性的一段经历、为什么投这个方向)和两三个反问(团队在做什么、这个岗位的成长路径、技术栈与协作方式),否则很容易聊不到十分钟就结束。另外面试场地与形式(HR 办公室、临时安排)说明这可能是小团队或初创,正规性不是唯一判断标准,但可以在反问环节确认团队规模、汇报关系与业务阶段,用来判断这个机会值不值得去,同时避免「没有下文」时无从复盘。