“你项目里Redis到底用来干嘛了”——就这一句话我见过太多候选人在面试现场卡壳。不是他们没学过是学的东西和真实项目之间隔着一层窗户纸。这几年我前后参加过上百场技术面试也带过不少新人越来越清晰地感觉到Java后端面试早就不考“背答案”了它考的是你在真实工程里拿到一个模糊需求后能不能拆出清晰的技术方案并且顶得住一连串追问。这篇文章就是想以“面试流程准备”为主线把Java后端从基础八股、框架原理、项目包装、系统设计到现场答题的完整链路梳理一遍。适合正在准备校招或社招的同学也适合带新人的同学拿来当作checklist。围绕“Java面试题”、“Java后端学习路线”、“前后端分离项目实战”、“后端面试八股文”、“若依框架”、“高可用场景”、“跨域处理”这些高频词来做展开每个部分都给到可以直接拿去用的准备方法和踩坑记录尽量做到少走弯路。1. Java核心功底的复习顺序与深度控制1.1 集合与并发最容易被追问的两块硬骨头Java基础部分是整个面试的地基但很多人的准备方式有问题一上来就背“八股文”背得滚瓜烂熟一追问就露馅。我面过不少候选人能流畅说HashMap的put流程但问他“自己实现一个线程安全的缓存你会怎么设计”就卡住了。这就是典型的“背了原理不会用原理”。先说集合。HashMap肯定是必考但面试官问的不只是“底层结构是什么”而是会一层层追问JDK 1.8的HashMap在什么情况下会从链表转红黑树为什么阈值是8resize扩容机制是怎样的多线程环境下为什么会出现死循环JDK 1.7为什么重写equals必须重写hashCode和HashTable、ConcurrentHashMap的区别是什么ConcurrentHashMap是怎么保证线程安全的这些细节看起来碎但其实有一条逻辑线hash计算 → 寻址 → 冲突处理 → 扩容 → 并发安全。复习的时候围绕这条线去看源码比死记硬背有效得多。ConcurrentHashMap至少要能说清楚JDK 1.7的Segment分段锁和JDK 1.8的CAS synchronized的差异还要能解释为什么1.8改用synchronized而不是ReentrantLock。再说并发。JUC包是面试的重灾区也是高并发项目经验的底层支撑。我建议按这个顺序复习volatile的可见性和禁止指令重排以及它和synchronized的区别synchronized锁升级过程偏向锁 → 轻量级锁 → 重量级锁JDK 1.6之后的优化AQS原理以及基于AQS的ReentrantLock、Semaphore、CountDownLatch线程池的七大参数、四种拒绝策略以及核心线程数怎么设置ThreadLocal的原理、内存泄漏问题以及使用场景有几道比较经典的追问直接决定你能不能过这一关线程池核心线程数是10任务队列是100现在来了200个任务会发生什么如果核心线程数设置为0呢这道题的坑点在于线程池的“先放队列再开线程”机制核心线程满了之后任务先进队列队列满了才会创建非核心线程再满才走拒绝策略。很多人下意识以为是“先开线程再排队”答反了基本就结束了。还有一道是ThreadLocal相关的“为什么ThreadLocal会有内存泄漏风险怎么避免”这个问题的核心是ThreadLocalMap的key是弱引用value是强引用。如果ThreadLocal对象被回收了value还挂在Map里线程一直存活比如线程池里的线程就回收不掉。标准做法是用完调用remove()。这些题的价值不在于“背答案”而在于帮你在脑子里建立一套“并发安全”的思维模型。写后端代码的时候哪里要加锁、哪里能用CAS、哪里用并发集合替换普通集合这套思维模型会直接决定代码质量。1.2 JVM与调优不背参数背排查思路JVM部分是很多人的痛点尤其是没做过线上问题排查的同学看到“JVM调优”几个字就发怵。其实面试官不是非让你报出一堆参数而是想确认你对着一个“内存飙高、CPU打满”的线上事故知不知道从哪里下手。知识层面要搞定这几块运行时数据区堆、虚拟机栈、本地方法栈、方法区元空间、程序计数器。要能画出来能说清谁线程私有、谁线程共享。垃圾回收算法标记-清除、标记-复制、标记-整理分代收集理论。垃圾回收器CMS和G1是重点。G1的Region布局、可预测停顿时间模型要能讲清楚。ZGC了解即可但最好知道它的染色指针和读屏障。类加载机制双亲委派模型以及打破双亲委派的场景Tomcat、JDBC驱动、SPI。常用排查命令jps、jstat、jmap、jstack、jinfo以及Arthas的基本用法。实际操作层面其实更重要。我准备面试时做过一套“线上故障排查模拟”很推荐大家照做一遍写一个死循环代码让CPU打满用top找到高CPU进程再用top -Hp找到高CPU线程最后用jstack导线程栈定位问题代码。写一个不断往List里加对象的程序制造堆内存溢出用jmap导出堆dump用MAT或VisualVM分析大对象。模拟线程死锁用jstack看线程状态找到互相等待的锁。这一套练下来面试官问“线上OOM怎么排查”“CPU飙高怎么定位”这类题你就有画面了不是凭记忆在挤概念。JVM参数的背诵不是重点但基础参数还是要知道-Xms、-Xmx、-Xmn、-XX:MetaspaceSize、-XX:MaxMetaspaceSize、-XX:UseG1GC这些能解释为什么-Xms和-Xmx通常设置成一样大小避免运行期堆扩容带来的性能抖动和资源抢占。顺带说一句很多人会忽略“类加载”这块。面试官问“一个类从加载到使用的过程是怎样的”很多候选人只能说出“加载、连接、初始化”但再往下问验证、准备、解析三个子阶段分别干什么就答不上来了尤其是准备阶段为静态变量分配内存并设置零值这个点特别容易被问倒。1.3 面向对象与设计模式如何回答“你代码里用了什么设计模式”面向对象的三板斧——封装、继承、多态——属于入门知识但面试官考的不是定义而是“你的项目里哪里体现了多态”。设计模式是这种问法的重灾区。候选人说“我用了策略模式”面试官就会问“不用策略模式用if-else一样能实现你为什么要用策略模式带来了什么好处”这个问题要答好光背类图是不够的得真正理解策略模式在解决“分支逻辑和业务规则的耦合”问题。结合“Java策略模式多种组合”这个热点词我强烈建议大家准备一个真实的组合场景。最常见也最好用的是“订单类型 支付方式”订单有多种类型普通订单、秒杀订单、团购订单。每种订单在创建、支付、取消、超时关闭等节点行为不同。如果用if-else每增加一个订单类型就要改一堆分支风险很大。用策略模式 工厂模式每种订单类型一个策略类通过一个Map根据类型获取对应策略新增类型只需新增类不用动老代码。“多种组合”的意思是策略模式往往是叠加的比如策略模式里套模板方法模式或者用工厂模式来创建策略对象。能把“策略 工厂”讲清楚再补充一句“如果策略类很多还可以用注解 反射的方式做策略自动注册”面试官一般就会觉得你有实战经验而不只是背过书。还有装饰器模式和责任链模式在Java面试里出现频率也很高。装饰器模式对应IO流体系责任链模式对应Filter和Interceptor的执行过程、Netty的Pipeline。尤其是Filter和Interceptor的区别几乎是后端必考题要能说清楚Filter是Servlet规范里的基于函数回调在请求进入Servlet之前/之后执行作用于所有请求。Interceptor是Spring MVC提供的基于反射和AOP只拦截Controller请求能拿到HandlerMethod可以访问Spring容器里的Bean。执行顺序是Filter → Interceptor.preHandle → Controller → Interceptor.postHandle → Interceptor.afterCompletion → Filter。2. 主流框架与工程生态从Spring Boot到若依2.1 Spring IoC和AOP不能只背定义要看启动流程Spring框架是Java后端的绝对核心面试准备没把Spring搞透基本等于白准备。我看过很多简历写着“熟练使用Spring Boot”但一问IoC容器是怎么启动的就只会说“配置文件加载Bean”这明显是停留在使用层面。面试官真正想听的是你能不能在宏观上描述一次完整启动过程在微观上说清关键机制。宏观层面的答案大概是这样Spring Boot启动时首先创建SpringApplication实例然后调用run()方法通过SpringFactoriesLoader加载META-INF/spring.factories里的自动配置类接着创建ApplicationContextServlet环境对应AnnotationConfigServletWebServerApplicationContext调用refresh()方法完成Bean的创建和初始化最后启动内嵌的Tomcat、发布ApplicationReadyEvent事件。refresh()方法里藏着Spring的生命周期核心至少要知道这几步是在干什么prepareRefresh刷新前的准备工作设置启动时间、激活profile。obtainFreshBeanFactory解析配置类注册BeanDefinition。Spring Boot里主启动类上的SpringBootApplication会触发组件扫描。prepareBeanFactory设置类加载器、SpEL解析器注册Environment等单例Bean。invokeBeanFactoryPostProcessors执行BeanFactoryPostProcessor其中ConfigurationClassPostProcessor负责解析Configuration、Bean、Import、ComponentScan这些注解。registerBeanPostProcessors注册BeanPostProcessor为后面的AOP、Autowired注入做准备。finishBeanFactoryInitialization实例化所有非懒加载的单例Bean这里会触发Autowired注入、PostConstruct初始化、以及代理对象的生成。有了这条主线你再去看Autowired为什么能注入、Transactional为什么能生效、Spring Boot为什么能自动配置就都能挂载到这条主线上来理解。AOP这块我说一个很多候选人栽跟头的地方Transactional在同一个类里方法自调用会失效。原因是Spring AOP基于动态代理自调用走的是this.method()而不是代理对象的调用所以事务增强逻辑没被执行。解决方案有三种注入自身代理、拆到另一个类、用AopContext.currentProxy()。面试官问这个表面考事务实际考的是AOP底层原理。还有CGLIB和JDK动态代理的差异。Spring Boot 1.x时代默认用JDK动态代理接口代理Spring Boot 2.x之后默认CGLIB。要注意的是Spring Boot 2.3之后spring.aop.proxy-target-class默认值是true所以默认走CGLIB不需要接口也能代理。CGLIB通过继承目标类并重写方法来实现增强所以被代理的类和方法不能是final的。2.2 前后端分离与跨域面试官最爱问的工程细节翻开近两年的Java后端热词几乎绕不开“前后端分离项目实战”、“后端跨域”和“Vue3怎么连后端”。这其实反映了行业现状后端工程师的日常早就不是单纯写接口了跟前端联调、处理跨域、协调接口方案是每天都要面对的事。先说“前后端分离”这个基本概念。传统开发模式里前端页面是后端渲染的JSP/Thymeleaf模板由后端填充数据再返回浏览器。前后端分离之后前端项目单独部署比如Nginx静态服务后端只提供JSON接口两者通过HTTP协议通信。面试官问你前后端分离的本质简单说是“关注点分离”和“解耦”——前端负责交互与渲染后端负责数据处理与业务规则二者可以独立开发、独立测试、独立部署、独立扩容。那分离之后最容易遇到的问题就是跨域。理解跨域要从浏览器的“同源策略”说起协议、域名、端口任何一个不同跨域就成立了。比如前端跑在localhost:8080后端跑在localhost:9090端口不同浏览器就会拦截。后端解决跨域最轻量的方案是CORS。Spring Boot里一个简单的方式是写一个WebMvcConfigurer配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }但有个关键点如果接口做了登录认证使用了Cookie/Session机制allowedOrigins不能直接用*必须用allowedOriginPatterns配合allowCredentials(true)否则浏览器会拒绝携带凭证的跨域请求。这个坑特别多人踩——他们说“按教程配了CORS但前端还是抱跨域错误”大概率就是“通配 凭证”冲突。还有一个面试常问的点为什么有时候一次请求在浏览器Network里会出现两个请求一个method是OPTIONS一个才是真正的GET/POST因为复杂请求比如Content-Type为application/json、携带自定义Header会先触发浏览器的预检请求后端必须正确响应OPTIONS否则真实请求根本发不出去。如果后端有全局拦截器或过滤器要注意放行OPTIONS请求否则预检请求会被拦下来前端看到的就是跨域报错。再说“Vue3怎么连接后端”。现在企业项目里最常见的组合是Vue3 Vite Axios Spring Boot。Vite开发模式下可以在vite.config.js里配proxy代理把请求转发到后端这样开发环境下浏览器看到的是同源请求根本不会跨越域export default defineConfig({ server: { proxy: { /api: { target: http://localhost:9090, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } })这层代理的原理是Node服务器作为中间层转发HTTP请求浏览器只跟Vite开发服务器通信自然没有跨域问题。生产环境则通常由Nginx做反向代理转发/api路径到后端服务。如果面试官问到“你平时怎么跟前端联调”不要只说“用Postman测试接口”可以说我们前后端会先通过Swagger/OpenAPI约定接口文档联调时前端通过Vite proxy或Nginx代理访问后端开发环境后端开CORS兜底生产环境统一走Nginx。这样既解决了跨域也避免了把CORS配置直接暴露在生产环境。2.3 若依这类快速开发框架在面试中怎么讲近几年“若依框架前后端分离”在Java后端项目里出现频率非常高。很多应届生或者转行的同学项目经验里都喜欢带上若依因为它开箱即用有权限管理、代码生成器、定时任务、多数据源等模块能在短时间内搭建一个看起来还挺完善的企业级系统。但在面试里提到若依有两个极端一种是把若依当成自己的“原创项目”面试官一追问底层就露馅另一种是只用若依做过二次开发但完全讲不出技术含量。这两种都拿不到高分。我的建议是若依是一个脚手架和载体你的价值要体现在“基于若依二次开发时做了什么”。面试官真正想听的是你在这个框架基础上如何理解它的设计如何解决业务问题。若依框架有几个值得深入掌握的技术点RBAC权限模型基于角色的访问控制用户-角色-菜单三层关系。若依前端路由根据后端返回的动态路由表生成按钮权限通过v-hasPermi指令控制后端通过PreAuthorize注解校验。代码生成器原理从数据库表结构反向生成Entity、Mapper、Service、Controller、Vue页面。这里可以体现出你对MyBatis Generator、Velocity模板引擎的理解。多数据源实现基于Spring的AbstractRoutingDataSource动态路由用DataSource注解配合AOP切换数据源。定时任务基于Quartz可以动态创建、暂停、恢复任务。如果你在若依基础上做过二次开发要重点讲清楚你做了什么。比如改造成了多租户架构在原有RBAC基础上增加了租户维度数据隔离通过SQL拦截器自动拼接tenant_id条件——这就是一个很有分量的增量改动。接入了某第三方支付或短信服务自己封装了统一调用SDK设计了回调通知的重试机制——这也是加分项。使用Redis替换了原有的本地缓存Session实现了集群部署下的会话共享。很多人看不起“二次开发项目”觉得没有含金量。实际上能不能在已有框架上做正确的扩展恰恰是真实工作里最核心的能力。企业里没有哪个项目是让你从零写起都是在已有系统上做演进。所以把若依的源码读进去能讲清楚它的权限设计、动态路由、代码生成思路这本身就是很好的面试素材。3. 项目经历包装把CRUD讲成有深度的工程技术3.1 项目选择与其堆砌不如深挖一个项目经历是面试成败的分水岭。基础题答得好说明你会背书项目讲得好说明你真的会干。我见过太多简历写了三四个项目每个都只有一句话“基于Spring Boot Vue开发的某某管理系统”这种项目在面试官眼里等于零因为看不到思考看不到难点看不到数据量。项目贵精不贵多一个是够用的但必须做深。什么叫“做深”不是说你用了多少分布式组件而是你能讲清楚每一个技术选型背后的取舍并且能扛住追问。举个例子同样是“用户登录模块”初级答案是“用户输入用户名密码我用MD5加密后查库校验”。进阶答案则是项目里有用户表千万级数据量登录接口有性能要求不能每次请求都查数据库。所以登录后生成了JWT令牌Redis里存会话信息设置了过期时间并做了续期策略。密码用BCrypt加密而不是MD5因为MD5是快速哈希暴力破解成本太低BCrypt内部自带盐值且计算慢对抗暴力破解效果好。为了提高安全性增加了登录失败次数限制连续失败5次锁定账号10分钟并做了图形验证码防机器人。多端登录时旧设备的Token通过Redis里的版本号直接失效。你看同样一个功能深度完全不同。面试官问你项目的时候不是想听你调通了多少个接口而是想知道你在技术上有没有独立思考有没有主动往工程化方向做。我给大家一个“讲项目”的标准模板背景项目为什么做解决什么问题业务量级大概多少用户量、数据量、QPS预估架构整体技术选型是什么为什么选这些组件画出系统架构图。职责你负责的核心模块是哪块为什么这块是难点方案针对难点你的解决方案是什么有哪些备选方案为什么做这个选择量化结果改造后接口响应时间从多少降到多少支撑的并发量大概什么量级反思如果重做一遍哪里会做得不一样把这个模板填满项目这一关基本稳了。注意第5点有数据一定说数据哪怕是你压测压出来的数据也比你空口说“性能提升了”有说服力得多。3.2 从登录权限到多租户一个可复用的项目演进路线如果你现在手里没有合适的项目或者说现有的项目太单薄我推荐一条可复用的“演进路线”每一步都能讲出技术和业务价值第一步搭一个基于Spring Boot Vue3 MyBatis-Plus的前后端分离基础项目把用户注册、登录、JWT认证、RBAC权限管理做扎实。这里就可以参考若依的权限设计思路但不要满足于“会用若依”要能自己从头实现一遍核心逻辑。第二步引入Redis做会话共享、验证码存储、接口幂等性控制顺便把缓存穿透、击穿、雪崩的解决方案在项目里落一遍。这一步出来后你就可以在简历里写“实现了基于Redis的分布式会话与热点数据缓存”。第三步引入消息队列RabbitMQ或RocketMQ二者学一个做一个异步场景比如下单后发送通知、积分累计。这时候就可以讲“削峰填谷”和“最终一致性”了。第四步引入Elasticsearch把项目的搜索功能从MySQL的LIKE查询迁移到ES讲清楚为什么MySQL在模糊搜索场景下性能不够。第五步加一个“多租户”的复杂度把单租户应用改成SaaS多租户模式。多租户隔离有三种方式独立数据库、共享数据库独立Schema、共享表加租户ID。共享表方案最适合做项目因为复杂度足够又能讲清楚SQL拦截器、MyBatis-Plus的租户插件、分布式环境下租户上下文传递等细节。第六步把项目往容器化推进写Dockerfile用Docker Compose编排MySQL、Redis、后端服务、前端Nginx有条件再接触Kubernetes。面试时讲到“我用Docker部署了一整套环境”立刻就能证明你真的把项目跑起来了不只是写写代码。这套演进路线走下来一个项目的技术深度已经不输很多公司的真实业务系统了。你不用做得很庞大但每一个环节都值得完整跑通、理解透彻。3.3 问答预演用数据说话用日志证明项目讲完面试官一定会进入“质疑环节”这个环节才是真正拉开差距的地方。常见问题包括“这个模块是你一个人写的吗”“这个方案有对比过其他方案吗”“这个性能数据是怎么测出来的”“如果用户量再涨十倍你的设计哪里会先撑不住”准备这些追问最好的办法是自己先“攻击”自己的项目。拿你写的接口为例一条一条问自己这个接口没有加缓存为什么加了缓存会有什么问题如果两个用户同时操作同一行数据你怎么保证数据一致某个第三方接口调用超时你的代码会怎么样如果Redis挂了系统还能用吗降级方案是什么你的事务边界划在哪里为什么会话级别放在这里数据库这张表数据量涨到一亿之后你的查询方案还成立吗这些问题不一定全都能答上来但必须在准备阶段就有自己的思考。我见过一个候选人被问“你这接口的QPS大概多少”他愣了一下说“没测过”面试官当场就不再追问了——因为一个好项目必须有数据支撑没数据等于没验证过。如果你没有生产环境的真实数据就用压测工具JMeter或者wrk自己压压出来的数据同样有价值单机部署下接口TPS大概多少数据库连接池配置多大瓶颈在哪个环节把排查过程讲出来这本身就是很好的面试素材。4. 系统设计与高可用后端代码不只是“能跑”4.1 高可用场景下写后端要注意哪些点近两年面试热度很高的一个问题方向是“在服务高可用场景下写后端代码时需要注意哪些点”这道题不是考你某个中间件怎么用而是考你作为后端工程师有没有一套完整的“容错心智”。可以从几个层次来回答第一层接口层面。外部依赖数据库、Redis、RPC服务不可用时你的接口会不会把异常原样抛给前端会不会导致线程阻塞在调用外部接口时要设置超时时间注意区分连接超时和读取超时。比如用RestTemplate或OpenFeign调用外部服务必须配置connectTimeout和readTimeout并且要考虑失败后的降级逻辑——是返回默认值、走缓存还是快速失败。第二层并发控制。高并发场景下单机代码要注意两点一是避免大对象的并发创建和锁竞争二是控制好线程池参数防止资源耗尽。比如我们处理大量异步任务时如果核心线程数设置过高会导致线程频繁切换系统吞吐量反而下降。第三层数据一致性。高并发下最典型的场景是“超卖”——库存扣减。面试官问“怎么防止超卖”别急着说Redis分布式锁先回答最基础的数据层方案扣减库存的SQL加上库存大于0的条件即UPDATE stock SET count count - 1 WHERE id ? AND count 0并且在事务内查出行级锁或乐观锁。第四层可观测性。高可用不只意味着不挂还意味着出了问题能快速定位。所以日志打点、traceId透传、慢接口监控、异常告警都是高可用的一部分。后端代码里要养成在关键路径打印结构化日志的好习惯。第五层自我保护。当系统压力超过阈值时要能限流和熔断。限流常见算法有计数器、滑动窗口、令牌桶、漏桶大多数场景用Google Guava RateLimiter或Sentinel就够了。熔断可以用Resilience4j或Sentinel核心思想是“调用失败率达到阈值后直接短路不再发起真实调用给下游喘息时间”。这个问题的回答框架我建议用“入口层 → 业务层 → 数据层 → 依赖层”来组织每一层各说一个核心动作面试官会认为你有全局意识而不是只知道零散组件。4.2 缓存、消息队列、分布式锁经典设计题的答题框架高可用和分布式这两块是Java后端中高级面试的“硬核区”。常见的题目类型包括Redis缓存穿透、击穿、雪崩的区别与解决方案这是必考中的必考。如何保证缓存和数据库的数据一致性如何处理消息重复消费消息堆积怎么办分布式锁用什么实现Redis的SET NX和Redisson有什么区别分布式事务的几种方案2PC、TCC、可靠消息最终一致性。每一道题都需要框架清晰。以“缓存与数据库一致性”为例我的回答思路是问题根源是两套存储之间作不了事务所以任何方案都只能降低不一致概率无法做到绝对一致。业界主流方案是“Cache Aside模式”读的时候先读缓存读不到读数据库再回填缓存写的时候先更新数据库再删除缓存不是更新缓存。为什么删除而不是更新因为更新缓存是写操作容易和并发读产生竞争而删除缓存会让下一次读重新加载实现起来更简单也更不容易出错。那为什么“先更新数据库再删除缓存”也可能有问题因为删除缓存可能失败如果删缓存失败就等于缓存里一直是旧数据。解决思路是引入重试机制比如把删除失败的消息发给MQ由消费者重试或者订阅MySQL的binlog做异步清理。如果要更严谨可以聊“延迟双删”——先删除缓存、更新数据库、休眠一小段时间再删除一次缓存但延迟双删其实也是补偿手段不是完美方案。这类题目要特别注意面试官问的是“你怎么做”不是“标准答案是什么”。在用“先更新数据库再删缓存”之后如果能主动补一句“这个方案要求删除操作必须可靠所以我会在删除失败时走重试或者在极端场景下接受一个短暂的缓存不一致窗口”就会比机械背诵答案强得多。消息队列的“重复消费”问题也是必考。答案是消费逻辑要“幂等”要么在数据库层面做唯一约束要么用Redis setnx做消费记录要么在业务代码里先查后插。最通用的方案是“全局唯一业务ID Redis去重”消息带一个订单编号消费者先SETNX一个key如果成功说明第一次消费处理完成后存结果如果失败说明已经处理过直接ACK并跳过。4.3 数据库设计与慢SQL排查Java后端面试数据库的比重一直在上升。“分库分表”、“索引失效”、“慢SQL优化”这几个关键词几乎必定出现。先谈索引失效这是基础中的基础。最常考的几条最左前缀原则联合索引(a, b, c)情况下直接查第二条条件b会失效。范围查询会使右边的索引失效。对索引列使用函数或表达式计算会使索引失效。LIKE以通配符开头的查询会使索引失效。字符串类型和数字类型比较MySQL会做隐式类型转换导致索引失效。很多人能背出这几条但实际问题是“给你一条SQL你判断会不会走索引”。所以我建议多刷场景题把SQL自己写出来用EXPLAIN看执行计划观察type级别是不是从ALL变成ref或range。type字段的访问顺序要记住system const eq_ref ref range index ALL覆盖到任何一档都要知道大概代价。再说慢SQL排查的整体思路开启慢查询日志定位慢SQL用EXPLAIN分析执行计划看有没有全表扫描、临时表、filesort针对性加索引或改写SQL。这条思路在面试里可以用“我排查过一个慢SQL”的真实经历来串联比背十篇文章都强。关于分库分表常见问题有分片键怎么选择扩容时数据怎么迁移分页查询怎么办跨节点join怎么解决这些问题的答案不是让你真的去搭一套ShardingSphere而是考察你有没有“分布式数据拆分”的思维方式。回答时抓住核心“分片键的选择决定了数据分布均匀性和查询路由效率尽量选业务上查询最频繁且分布均匀的字段”。5. 面试实战从简历投递到现场答题5.1 简历怎么写关键词、量化指标、项目拆解简历是面试的敲门砖很多技术能力不错的人挂在简历筛选环节非常可惜。Java后端的简历我建议抓住三个关键点第一关键词必须对齐JD。如果是“前后端分离项目实战”相关的岗位简历里要明确写“Vue3 Spring Boot MyBatis-Plus Redis”这类技术栈名词如果岗位要求高并发经验简历里要有“消息队列削峰”、“缓存降低数据库压力”、“分布式锁”这些字样。简历筛选很多时候是第一轮机器过滤/HR关键词筛选完全避开关键词等于自杀。第二每个项目经历要用“技术挑战 解决方案 量化结果”的结构来写。不要写“负责用户模块的开发”这种没有信息量的话要改成“设计并实现了基于JWT的登录鉴权模块通过Redis存储会话实现集群环境下的登录状态共享单接口压测TPS从800提升到1200”。第三所有写在简历上的技术点你都要准备好被追问。写了Elasticsearch就要准备好回答“ES为什么搜索快”“分词器怎么选的”“深分页问题怎么处理”。写了消息队列就要准备好回答“消息丢失怎么处理”“顺序消息怎么处理”。简历不是装饰品是你给自己划的考试范围。5.2 八股文的正确背法“Java面试八股文”这个词现在非常流行但我第一次听到就有点不舒服因为它给人一种“死记硬背就能拿offer”的错觉。事实上靠机械背诵过面试的同学入职后往往适应得很痛苦因为真实工作中没有“标准答案”。正确背八股文的方式不是背结论而是背“推导链”每个概念你要能自己解释清楚“为什么是这样”。比如回答“为什么HashMap线程不安全”如果你能推到“resize时并发put可能导致环形链表”这种推导能力就是有价值的。但如果你只能说出结论不知道怎么推导面试官追问两个“为什么”就露馅了。另外一个很有效的复习方法是“费曼学习法”的变体——默写。每天挑三个知识点把它们当成给新同事讲技术文档一样口头或笔头默写出来尽量讲得通俗、结构清晰。默写时卡壳的地方就是你记忆最薄弱的地方重点回炉。我准备面试那会儿每天坚持默写30分钟一个多月下来效果非常明显。注意“八股文”不是不可以背而是要先理解再背。像JVM内存模型、垃圾回收算法、AQS原理这些内容如果完全凭理解去组织语言面试现场很容易语无伦次这时候背几个标准句式、把逻辑主线烂熟于心其实是提高表达稳定性的好办法。5.3 手撕算法与代码题从冒泡排序到并发工具Java后端的算法面试强度通常低于算法岗但手撕代码是跑不掉的。准备范围我建议包括基础排序冒泡、选择、插入、快排、归并。快排和归并要能手写并说清复杂度。常用数据结构数组、链表、栈、队列、哈希表、二叉树。字符串处理反转、最长公共前缀、括号匹配。动态规划和贪心爬楼梯、最大子数组和、零钱兑换。多线程编程题两个线程交替打印、三个线程顺序打印、生产者消费者。注意Java后端面试的手撕题有时候不是纯算法题而是“带工程场景的小题”。比如请手写一个生产者-消费者模式要求使用BlockingQueue。这种题目并不难但它考的是你对并发工具类的掌握程度。用ArrayBlockingQueue实现几行代码能搞定但要能答出为什么用BlockingQueue而不用wait/notify——因为BlockingQueue内部已经封装好了锁和条件队列降低了出错概率。还有一道很经典的手撕题用两个线程交替打印1到100要求线程A打印奇数、线程B打印偶数。常见解法是用synchronized wait/notify或者用volatile标志位自旋再高级一点用CompletableFuture或者两个信号量Semaphore。面试时能给出两种以上方案并说出各自的优缺点是很好的加分表现。算法题准备还有一个长期策略刷题不要按顺序刷按“题型专题”刷。两周刷完一个专题比如双指针、二叉树递归、动态规划比一天刷十道乱序题有效得多。我自己的经验是把LeetCode Hot 100刷两遍再把多线程相关的题目单独过一遍应付绝大多数Java后端手撕环节足够了。6. 常见问题与复盘记录把自己训练成面试型选手6.1 常见高频问题速查表把高频问题整理成一张速查表复习时对照着检查自己查缺补漏特别有效。这里列一份我整理的Java后端面试高频问题清单分模块附上关键回答要点模块典型问题回答突破口Java基础HashMap的put流程扰动函数取hash、寻址、插入链表/红黑树、扩容Java基础和equals的区别前者比较引用后者比较内容重写equals需重写hashCode并发synchronized和ReentrantLock的区别锁实现、公平性、可中断、Condition、锁释放方式并发ThreadLocal内存泄漏弱引用key 强引用value使用remove清理JVM什么时候触发Full GC老年代空间不足、元空间不足、晋升失败、System.gcJVM怎么排查OOM先知道哪个区域OOMjmap导dumpMAT分析SpringAutowired和Resource区别前者按类型注入后者默认按名称注入Spring循环依赖怎么解决三级缓存提前暴露早期引用Spring Boot自动配置原理SpringFactoriesLoader 条件装配数据库事务隔离级别读未提交、读已提交、可重复读、串行化数据库数据库死锁怎么办查看innodb_status分析锁等待优化加锁顺序Redis缓存穿透、击穿、雪崩布隆过滤器/空值缓存、互斥锁/逻辑过期、随机过期时间/多级缓存RedisRedis为什么快纯内存、单线程避免锁竞争、IO多路复用、高效数据结构系统设计怎么设计一个短链接系统发号器、哈希、缓存、重定向、过期清理系统设计怎么设计秒杀系统限流、削峰、异步扣减、防超卖、静态化这张表不是让你背而是照镜子用。看到一个问题能立刻在脑子里组织出完整回答链路就算过关如果看着卡壳就翻回对应章节补功课。6.2 面试复盘面完不是结束是开始很多人面试完就松一口气过两天问结果没过也不知道为什么。这是最大的浪费。不管面试结果如何当场都应该做两件事回忆并记录所有被问到的问题标注自己哪里答得好、哪里答得差以及更重要的是事后把自己的回答复盘一遍看是否完整、准确。我面完每一轮都会整理一份面试复盘表格式大致是基础题问了哪些我哪里答偏了项目题面试官对哪个项目追问最多我讲得够不够清晰场景题有没有我没准备过的方向下次怎么扩充手撕题用了多长时间有没有更优解复盘最神奇的地方在于你积累的“被追问的刁钻问题”几乎就是下一家公司面试官会问的问题。因为同一个知识点的追问模式是高度相似的别人问倒你的点换一家公司还会被问到。如果条件允许强烈建议做“模拟面试”。找同行的朋友互相提问模拟真实面试节奏体验被连番追问的压力这对临场心态帮助非常大。没有同行朋友的话自己用手机录音回放时你会发现自己很多口头禅、“嗯嗯啊啊”的空白对镜子演讲也是有效的训练方式。6.3 给自己排一个90天学习计划面试准备的战线短的两三周长的半年取决于你的基础和面试目标。如果给自己安排一个90天计划我建议这样切分前30天打基础。重点复习Java集合、并发、JVM、MySQL、Redis的理论内容配合面试高频率题做“理解 — 默写 — 复述”训练。同时每天刷2-3道算法题保持手感。中间40天做项目沉淀。把你简历上的核心项目按照第3章的模板重写一遍补充压测数据完善架构图。如果项目本身比较弱把演进路线里的Redis缓存、消息队列、多租户改造等模块依次加上。这期间遇到理论不清楚的技术点回头翻基础。最后20天模拟冲刺。按“自我介绍 — 项目讲解 — 基础题 — 场景题 — 手撕题 — 反问环节”的完整流程来做面试模拟每天至少一轮。把高频面试题一张一张背熟重点是掌握回答节奏每道题的回答控制在2-3分钟既不能像背书一样干巴巴也不能发散到跑题。面试前夜不用再学新东西把项目里的数据口径、你的三个核心亮点、两个最得意的技术方案记牢保证睡眠。剩下交给临场状态——你已经为了这次机会做了90天的准备它只是验收而已。我自己的体会是面试准备最大的价值往往不在面试本身而在于它逼迫你构建了一套完整的技术知识体系。很多平时写代码不太在意的问题比如“这个接口的TPS多少”“这条SQL的索引能命中吗”一旦开始认真准备面试你会带着全新的视角去看自己的工程代码。这个过程本身就是一次非常难得的能力跃迁。无论你最终是否去面试花一段时间按照这个思路梳理一遍收获的绝对不只一个offer。
