java面试题 4

📅 2026/7/2 23:52:27
java面试题 4
Java相关回答不足点整理以下专门筛选出两轮面试中Java/后端/数据库/中间件/架构方向回答不到位的地方按问题类别整理方便你集中复习。一、系统架构与微服务1. 网关鉴权API权限 数据权限——两场均暴露你的回答“鉴权这块可能不太清楚平时业务开发比较多不太关注。”问题所在在银行核心做Java开发近5年即使没亲自写过鉴权模块也应该知道基本链路。这个回答直接关上了话题面试官会认为你只盯着自己一亩三分地。需要掌握的基本链路网关层用Spring Security JWT做统一认证流程是用户登录 → 认证服务颁发JWT含用户ID、角色、权限列表后续请求携带JWT → 网关过滤器验证签名/有效期验证通过后在请求头中注入X-User-Id、X-Role等信息下游微服务通过拦截器获取这些信息做接口权限角色/权限码校验和数据权限只查自己部门/机构的数据通过SQL拦截器动态追加WHERE条件如果没实际做过至少要把这个链路背下来。2. 流量管控限流、削峰——第一场你的回答没答上来。问题所在你讲了贷款生命周期流程很长合同→计提→回收→账务面试官自然会问“流量这么大你们怎么做限流和削峰”你没接住。正确方向银行核心系统的流量治理通常分几层层级手段说明网关层Sentinel限流按API路径配置QPS阈值超出快速失败返回业务层线程池隔离 熔断降级不同服务用不同线程池下游故障时熔断消息层MQ削峰填谷高峰期请求先入MQ消费者按自身能力消费避免压垮数据库批量处理日切批处理错峰核心账务类操作放到夜间批处理窗口执行3. 分库分表的“架构视角”说不清楚——两场均被追问你的回答集中在技术实现上——internal key取模分4个库加DB number字段。面试官原话“你平时和你们架构聊肯定也不是这么聊的咱们可以再上升一下。”问题所在面试官想听的是分库分表的前置决策而不只是取模逻辑。正确方向先说业务再说技术“我们当时做新核心重构分库的背景有两个一是业务上要把贷款、存款、账务拆成独立的领域服务对应的库天然就分开了二是数据量太大单库扛不住。最终定了4个库分库键选了internal_key因为它全局唯一且均匀分布取模后数据分布比较均衡。分库后对上层业务透明——我们在DAO层封装了路由逻辑业务代码只需要传internal_key不用关心具体去哪个库。”先交代业务拆分原因再说技术实现这就是他们要的“上升”。二、分布式事务与一致性4. TCC vs SAGA的区别同步/异步、适用场景——第一场你的回答“链路长短不一样TCC链路短、SAGA链路长。”问题所在太浅了。面试官需要你讲清楚同步vs异步、业务侵入性、补偿机制的差异。正确的对比维度TCCSAGA同步/异步同步全程等待异步事件驱动资源锁定Try阶段锁定资源直到Confirm/Cancel释放不锁定资源先执行正向操作适用场景短链路、一致性要求极高如扣库存长链路、跨多个服务如贷款记账存款补偿方式Cancel回滚已锁定资源执行反向补偿操作业务侵入性高需实现try/confirm/cancel三个方法中需实现正向补偿两套逻辑优点强一致性可回滚不长时间占用资源吞吐量高缺点资源占用时间长并发能力受限最终一致需处理补偿失败的情况为什么银行核心用SAGA更多因为贷款发放链路涉及合同、计提、记账、存款等多个服务如果用TCCTry阶段要锁住所有资源用户等待时间长且并发能力差。SAGA先做正向操作默认成功失败了再补偿用户体验好代价是最终一致性——但银行可以通过日切对账来兜底。5. 幂等设计——第一场你的回答举了Redis宕机导致重复扣款的例子用数据库唯一索引做兜底。问题所在例子本身没问题但回答过于局限没有涵盖幂等的完整方案。需要掌握的系统性视角幂等应该做多层次拦截层级方案说明业务入口全局流水号 Redis去重SETNX请求进来先查Redis是否存在该流水号存在则直接返回上次结果数据库层唯一索引兜底Redis万一挂了DB唯一索引拦截重复插入消息消费端业务主键去重表MQ消费时先查去重表已消费则跳过注意你举的例子里Redis挂了导致重复扣款说明你们没有做数据库唯一索引兜底或者索引字段没覆盖到这笔交易。面试官可能会追问“那你们后来怎么解决Redis单点问题的”——可以考虑用Redis Cluster或引入本地缓存做二级缓存。三、数据库与索引6. 索引设计太“八股”缺少场景化案例——第一场被反复追问你的回答B树结构、聚簇索引/二级索引、覆盖索引、回表、左前缀原则、少用函数、小表驱动大表……面试官原话“你说的都没问题但我听不太出来你是真的在业务里做过。能不能给我讲一个你真实的场景”问题所在所有知识点都对但缺少一个你自己的设计案例听起来像在背书。你需要准备一个自己的案例比如这样“我当时在数据迁移时遇到一个慢查询账户交易流水表trans_hist4000万数据高频查询条件是WHERE account_no ? AND trans_date BETWEEN ? AND ? ORDER BY trans_time DESC。原来三个字段各有一个单列索引但EXPLAIN发现每次只用到account_no索引然后回表查trans_date和trans_time平均耗时1.8秒。我改成联合索引(account_no, trans_date DESC, trans_time DESC)查询耗时降到40ms。原因是①覆盖了查询所需字段不用回表②trans_date和trans_time按降序排列省去了额外排序。缺点是写入慢了约15%但这张表读多写少业务可接受。”有表名、数据量、优化前后数字、选择的权衡才是他们要的场景化回答。7. 笛卡尔积的触发条件——第二场你的回答“记不清了。”这是送分题不应该丢。正确答案-- 1. 没有连接条件SELECT*FROMtable_a,table_b;-- 2. 连接条件恒为真11 或 无效条件SELECT*FROMtable_a aJOINtable_b bON11;-- 3. 显式使用 CROSS JOINSELECT*FROMtable_aCROSSJOINtable_b;-- 4. 左连接/右连接时连接条件写错导致匹配到所有行面试官问这个不是在考你记不记得语法而是想确认你对SQL执行计划的基本认知——连表时如果没有有效的ON条件优化器只能做笛卡尔积性能灾难。笛卡尔积触发条件 —— 问题复盘与清晰答案你当时的回答面试官“连表查询的时候什么时候会出现笛卡尔积”你的回答“连表查询产生笛卡尔积一般也是因为它是SQL的话它是有三范式的嘛就是说有点记不清了。”为什么这个回答很可惜这是一个极基础的送分题答案本身不超过3句话。你如果在这里卡住面试官的判断会是SQL基本功不扎实 —— 连表查询是后端开发日常操作触发笛卡尔积属于最基础的认知面对简单问题缺乏推导能力 —— 即使忘了具体场景也可以根据原理推导出来直接放弃“记不清了”而不是用已知知识推理 —— 面试官会认为你解决问题的意愿不足实际上哪怕你完全没背过答案也可以现场推理出来“笛卡尔积就是两表所有行两两组合。那什么情况下SQL会把所有行两两组合当查询没有告诉数据库怎么关联的时候。所以要么是没写连接条件要么是连接条件恒成立。”能说出这句话就不用背任何代码面试官也会认可你的逻辑能力。完整清晰的正确答案一句话核心定义笛卡尔积Cartesian Product是指对两张表进行连接查询时没有有效的关联条件导致左表的每一行与右表的每一行逐一组合结果集行数 左表行数 × 右表行数。举例A表有1000行B表有500行产生笛卡尔积 → 返回 500,000 行即使这50万行里99.99%都是无意义数据。触发笛卡尔积的4种典型场景场景1完全没有连接条件-- 没有任何WHERE或ON来限定关联关系SELECT*FROMtable_a,table_b;数据库不知道两表怎么关联只能把所有行交叉组合。场景2连接条件无效/恒为真-- ON条件是常量11永远成立SELECT*FROMtable_a aJOINtable_b bON11;-- 或者使用了无效表达式SELECT*FROMtable_a aJOINtable_b bONa.无效字段b.任何值;-- 字段不存在→被忽略→全连接场景3显式使用 CROSS JOIN-- CROSS JOIN 的语义就是笛卡尔积SELECT*FROMtable_aCROSSJOINtable_b;这是有意为之的笛卡尔积少数场景如生成测试数据、穷举组合会主动使用。场景4连接条件写错导致一对多膨胀近似笛卡尔积-- 本该用唯一键关联结果用了非唯一字段-- 例如 table_a.customer_type 只有2种类型(个人/企业)-- table_b.customer_type 也有2种类型-- 每个customer_type下各有大量行关联后数据量膨胀巨大SELECT*FROMtable_a aJOINtable_b bONa.customer_typeb.customer_type;这种情况下不是严格的笛卡尔积因为有限制条件但效果类似——结果行数远超预期性能同样灾难。它本质上是对连接条件选择性过低缺乏警惕可以用“近似笛卡尔积”来向面试官说明。如何发现笛卡尔积-- 在执行SQL之前先用 EXPLAIN 查看执行计划EXPLAINSELECT*FROMtable_a,table_b;EXPLAIN输出中如果看到Using join buffer (Block Nested Loop)—— 没有索引可用在做全表扫描连接filtered列值极低rows列显示table_a行数 × table_b行数级别的扫描行数基本就是笛卡尔积了。避免笛卡尔积的方法方法说明写连接条件多表查询必须带有效的ON或WHERE关联条件用小表驱动大表JOIN顺序上先连数据量小的表再连大表减少中间结果集关联字段加索引被关联的字段如外键建索引让优化器走Index Nested-Loop Join避免全表扫描审查执行计划提交SQL前用EXPLAIN看一眼扫描行数是否合理避免隐式连接混用不要把逗号连接和JOIN混在一起写容易漏条件如果面试时真的忘了怎么办现场推导法你可以说“我具体场景可能记得不太清了但我可以推一下。笛卡尔积的本质是两表行两两配对那产生的原因一定是查询没有给数据库一个有效的连接依据。所以大概率是①没写WHERE或ON条件②写了条件但条件恒为真比如 ON 11③用了CROSS JOIN这种显式全连接。我一般在开发和代码审查时会特别注意这一点避免生产环境出现慢查询。”这样即使细节记不全面试官也会认为你理解原理而不是死记硬背。与银行核心业务场景的结合加分如果你能把笛卡尔积和你的银行数据迁移经历联系起来会更有说服力“我在做数据迁移时遇到过一个具体案例抽数SQL中有一张10亿的交易流水表trans_hist和一张账户表account做JOIN连接条件本应是 trans_hist.account_no account.account_no但有人把条件写成了 trans_hist.trans_date account.open_date导致一条账户记录匹配到几千条流水跑了40分钟没出结果。我们后来用EXPLAIN发现rows估算显示笛卡尔积量级修正条件后降到2秒。从那以后我们团队所有连表SQL都会先过EXPLAIN审查。”这个案例同时展示了业务场景 问题发现手段EXPLAIN 优化效果40分钟→2秒 团队规范改进比单纯背语法要强十倍。8. 缓存穿透/击穿/雪崩的概念混淆——第二场你的回答穿透传一个不存在的值 → 用布隆过滤器 ✅击穿查了一堆过期的 → 把过期时间设置大一点 ❌雪崩集体过期 → 过期时间加随机数 ✅问题所在“击穿”和“穿透”的概念你没区分清楚把击穿说成了“查了一堆过期的”定义有误。正确区分概念定义解决方案穿透查一个缓存和DB都不存在的key每次都打到DB布隆过滤器 / 缓存空值如存并设短过期时间击穿一个热点key恰好过期大量请求同时打到DB互斥锁SETNX/ 逻辑过期提前异步刷新雪崩大量key在同一时间过期大量请求打到DB过期时间加随机偏移 / 多级缓存本地分布式“查了一堆过期的”更像是雪崩的极端情况而不是击穿的定义。四、中间件9. MQ消息积压的处理——第一场直接卡住你的回答“答不上来。”基础应对方案至少要说出来扩容消费者增加消费者实例但要确保Topic的分区数≥消费者数否则多余的消费者拿不到消息提高消费速率临时调大batchSize批量拉取、调高prefetchCount预取数量排查根因是下游DB写入慢还是消费者逻辑中有远程调用超时针对性优化临时降级先把积压消息转存到新Topic用更多消费者并行处理原Topic恢复后回补即使没实际遇到过至少要知道这4条思路。完全说“不知道”会让面试官觉得你只关心业务CRUD不关心系统稳定性。五、总结Java方向急需加强的TOP 5按两场面试暴露的严重程度排序优先级知识点为什么急建议行动1索引场景化案例两场都被追问但都没讲出具体案例准备一个真实的慢查询优化故事表名、字段、数据量、优化前后耗时2网关鉴权链路直接说“不知道”扣分严重背熟JWT→Gateway→下游拦截器的流程至少讲到能让人听懂3TCC vs SAGA 完整对比第一场被追问同步/异步回答太浅把上表中的对比维度记熟尤其要能结合你做的贷款业务讲为什么选SAGA4缓存三兄弟穿透/击穿/雪崩第二场概念混淆把定义和各自解决方案背准这是高频面试题5MQ积压处理思路第一场卡住把扩容消费者、调参、根因排查、临时降级4条记住即可应急另外提醒一点如果下次被问到不会的Java问题不要直接说“不知道”就结束。试着说“这个具体配置不是我在负责但我了解整体思路是……”——至少证明你有架构意识而不是完全空白。