Skip to content

面试问题清单


一、关于你整个简历的总问(开场必问)

  1. 如果 1 分钟内介绍自己,会突出哪些核心信息?

我是谁:
“我叫 xxx,计科大四,现在主攻 Java 后端。”

我会什么:
“熟悉 Spring Boot、MyBatis-Plus、MySQL、Redis,做过两个后台项目。”

我在项目里做什么:
“负责商品管理、菜品、缓存优化、分页筛选、异常处理这些核心接口。”

我有什么特点:
“动手快、排查问题稳、喜欢复盘,目前在找 Java 后端实习。”

  1. 你做过哪些项目?每个项目的目标与技术栈是什么?你负责的模块具体有哪些?

“做过外卖后台和商城后台两个项目。”

每个项目的目标:
“外卖项目是为了熟悉 Spring Boot 全流程;商城项目重点在 Redis 缓存和一致性处理。”

各自的技术栈:
“用到 Spring Boot、MyBatis-Plus、MySQL、Redis,按 MVC 开发接口。”

你负责哪些模块:
“外卖里负责菜品、分类、购物车和订单查询;商城里负责商品管理模块和 Redis 分类缓存。”

你做出的具体内容:
“写分页、筛选、上下架接口,做列表缓存、穿透处理、缓存精准清理,补全异常处理和响应封装。”

  1. 你平时如何规划自学与复盘?

你怎么学:
“把知识按大块拆开,先抓核心结构。”

你怎么用:
“用做中学的方法,把概念立刻写进实际接口里。”

你怎么复盘:
“遇到问题就记录,整理到博客里,把踩过的坑写成自己的流程。”

  1. 最近一次解决比较麻烦的问题是什么?如何定位并复盘?

问题是什么:
“商品分页不返回数据,但 SQL 是正常的。”

你怎么定位:
“打印日志看到前端给的是字符串状态,而数据库是 int,条件没匹配上。”

你怎么解决:
“加字段转换和参数校验,统一前后端字段类型。”

你怎么复盘:
“把‘前后端字段不一致’整理成一条复盘记录,后续接口提前规避。”

  1. 职业规划

短期目标:
“先拿到实习,进入真实项目环境。”

毕业后的目标:
“打牢后端基础,包括数据库、缓存、服务稳定性。”

一年后的目标:
“能独立负责小模块开发,进一步提升工程能力。”

二、商品管理模块(核心问区)

  1. 商品管理模块的整体流程是什么?

流程骨架:
“请求进入控制层,做参数校验 → 调用服务层处理业务 → 操作数据库 → 返回统一响应。”

对应内容:
“我把流程固定成 Controller 做校验与接参,Service 写业务逻辑与事务处理,Mapper 负责 MyBatis-Plus 的 CRUD,所有返回都走统一响应格式,便于排查问题。”

  1. 你负责的具体功能有哪些?

功能骨架:
“新增、编辑、分页、多条件筛选、分类过滤、上下架状态、缓存处理。”

对应内容:
“我主要负责商品的增删改查、分页和多条件组合查询,做了分类维度的列表缓存、变更后的缓存清理,还完善了状态字段、异常处理和 DTO 转换流程。”

  1. 新增商品的流程是什么?

流程骨架:
“接收 DTO → 校验 → 拷贝到实体 → 写库 → 返回结果。”

对应内容:
“新增时我先接收前端传入的商品 DTO,做基础字段校验,使用 BeanUtils 拷贝到商品实体,补充默认状态与时间,再通过 MyBatis-Plus 写入数据库,最后返回统一响应。”

  1. 编辑商品时你处理了哪些字段?

字段骨架:
“基本信息字段、分类、价格、库存、图片、状态。”

对应内容:
“编辑时我优先处理标题、描述、分类、原价与现价、库存、封面图,并保留创建信息,更新修改时间,同时确保状态字段在上下架逻辑里保持一致性。”

  1. 分页查询是怎么做的?

分页骨架:
“使用 MyBatis-Plus 的 Page 对象做分页 + 条件链式查询。”

对应内容:
“我在控制层接收 page、pageSize,用 MP 的 Page<Goods> pageObj 执行分页查询,在 service 构造 LambdaQueryWrapper,把分类、名称模糊、状态等条件统一封装,再返回分页结果。”

  1. 多条件查询是如何封装的?

骨架:
“用统一的查询对象,把可选条件按‘非空再拼接’的方式封到一个查询器里。”

对应内容:
“我用的是 MyBatis-Plus 的 LambdaQueryWrapper,把商品名称模糊查询、分类 id、状态这几个条件都写在一个方法里,判断参数不为空再追加条件,这样控制层只传一个查询 DTO,后续要加条件也只改这一处。”

  1. 分类过滤是怎么实现的?

骨架:
“前端传分类 id,后端按分类条件查询,并结合缓存做分类列表缓存。”

对应内容:
“列表查询时,前端会把 categoryId 传过来,我在查询 wrapper 里追加 eq 条件,只查该分类下的商品。同时我用分类 id 作为 Redis key 的一部分缓存这个列表,变更商品时按分类清理对应缓存,保证同一分类的数据是一致的。”

  1. 商品上下架状态怎么设计的?

骨架:
“用状态字段表示上架/下架,通过接口更新状态并联动缓存。”

对应内容:
“数据库里有一个 status 字段,用 int 或 tinyint 存,比如 1 表示上架,0 表示下架。上下架接口只改这个字段,不删数据,这样分页和列表查询都可以按 status 过滤出可售商品,同时在状态变更后按分类清理缓存,保证前端看到的都是最新状态。”

  1. DTO 转换的作用是什么?

骨架:
“把前端请求和数据库实体隔离开,便于参数控制和字段扩展。”

对应内容:
“我用 DTO 承接前端传入的字段,比如分页条件、表单数据,再通过 BeanUtils 或手动赋值转换成实体对象。这样可以避免直接暴露数据库字段,方便对外隐藏敏感字段、做字段裁剪和校验,也让以后改表结构时对接口的影响更小。”

  1. 你们的参数校验怎么做的?

骨架:
“简单的用注解做基础校验,复杂的在服务层做业务校验。”

对应内容:
“基础必填、长度这类我会在 DTO 上用校验注解,比如 @NotBlank、@NotNull、@Size,然后在控制层用 @Valid 触发校验;像价格不能为负数、分类必须存在这种业务规则,我会在 service 里单独判断,不符合就抛出自定义业务异常,这样既保证了数据合法性,也方便统一处理错误信息。”

  1. 表结构你为什么这样设计?

骨架:
“先按职责拆表,再保证字段原子性和可扩展性,常用条件加索引。”

对应内容:
“我把商品和分类拆成两张表,商品表只放名称、价格、库存、分类 id、状态、封面图、创建和修改时间这些与商品本身直接相关的字段;分类信息统一放在分类表,通过 category_id 关联。字段尽量保持原子性,方便后续做统计和扩展。像分类、状态这种高频查询条件我加了索引,这样既保证结构清晰,也兼顾查询效率和后续扩展。”

  1. 你怎么保证接口的可维护性?

骨架:
“严格分层、统一风格,把共用逻辑抽出来,避免写魔法值。”

对应内容:
“我在商品模块里按 Controller、Service、Mapper 做了清晰分层:Controller 只负责参数接收和结果返回,Service 里集中写业务逻辑和事务,Mapper 专门负责数据库访问;分页和多条件查询封装成统一方法复用,新增和编辑都走相同的 DTO 转换流程;状态值、错误码这些都用常量或枚举集中管理,避免在代码里到处写死数字或字符串,这样后续改字段、加条件只需要在固定位置调整,整体可维护性会高很多。”

  1. 你做过哪些异常处理?

骨架:
“用全局异常处理器兜底,区分参数异常、业务异常和系统异常。”

对应内容:
“我写了一个全局异常处理器,用 @RestControllerAdvice 统一捕获异常。参数校验相关的异常,比如字段为空、格式不对,会转成带具体提示的返回结果;业务逻辑里的非法操作,比如商品状态不允许上下架、库存不足,我会抛出自定义的业务异常,通过统一处理返回明确的错误码和信息;其它没预料到的系统异常会记录完整日志,只给前端返回通用错误提示,避免堆栈信息直接暴露,同时方便后续排查。”

  1. 你怎么定位联调阶段的问题?

骨架:
“先核对请求,再看日志和 SQL,必要时用工具复现请求逐步排查。”

对应内容:
“联调出问题时,我会先确认前端请求的 URL、方法、参数是不是和接口文档一致,然后在服务端日志里看入参、返回值和异常信息。有查询类问题,我会把实际执行的 SQL 打印出来,在数据库里单独跑一遍对比结果;如果怀疑是参数格式或字段类型不一致,我会用 Postman 按前端约定重放一遍请求,逐步排除是前端传参问题、后端校验问题还是数据本身有问题。这样基本能快速锁定问题出在哪一层。”

三、Redis 缓存(重点必问)

  1. 为什么要对商品列表做缓存?

骨架:
“高频查询不需要每次查数据库,缓存能显著减轻压力。”

对应内容:
“商品列表属于高并发访问的接口,分类页、首页、筛选区域都会频繁请求,如果每次都查数据库会增加延迟和压力,所以我把常用的分类商品列表缓存到 Redis,大部分请求可以直接命中缓存,提高响应速度。”

  1. 你的缓存 key 是怎么设计的?

骨架:
“按业务分类 + 参数拼 key,做到唯一且可控。”

对应内容:
“我把 key 设计成类似 goods:category:{id} 的格式,其中 id 是分类 ID。这样不同分类命中不同缓存,层级分明、可读性高,也便于更新商品时精准清理对应的缓存。”

  1. 你缓存哪些数据?

骨架:
“主要缓存列表类数据,不缓存强一致性的内容。”

对应内容:
“我主要缓存的是分类下的商品列表数据,比如某分类首页展示的商品集合,因为这些是高频读、低频写的场景。而像单个商品详情这种需要实时更新的,我会直接查数据库,不放缓存。”

  1. 缓存的过期时间怎么定?

骨架:
“结合业务读写比,设置合理 TTL,避免长期脏数据。”

对应内容:
“商品列表我一般设置短 TTL,比如 10 分钟左右,让缓存保持一定更新频率,同时避免旧数据长期存在;另外,商品变更时会主动删除缓存,因此 TTL 只是兜底策略,不依赖它来更新数据。”

  1. 商品更新后怎么保持缓存一致?

骨架:
“更新数据库后,按分类删除对应缓存,下一次自动重建。”

对应内容:
“商品新增、修改、上下架时,我会根据商品的分类 ID 直接删除 goods:category:{id} 这个 key,让下一次请求重新查数据库并写入最新的缓存,这样能保证列表数据和数据库保持一致。”

  1. 为什么采用“删缓存”的方式?

骨架:
“删除比更新更安全,能避免多点写入导致的脏数据。”

对应内容:
“因为列表缓存往往是多个字段组合而成的,如果用‘更新缓存’很容易漏掉某些情况或写错数据;用删除的方式,下一次查询会重新从数据库生成最新结果,简单稳定,不会出现缓存和数据库不一致的问题。”

  1. 空值缓存是什么?

骨架:
“把查不到的数据也缓存,让同样的非法请求不再打数据库。”

对应内容:
“比如查询某个不存在的商品 ID 时,我会缓存一个标记为空的值,设置很短的 TTL(几十秒)。这样同一个不存在的 ID 在这一段时间不会不断穿透到数据库,防止恶意或者错误请求造成压力。”

  1. 缓存穿透是什么?

骨架:
“请求的数据本身不存在,导致每次都绕过缓存打数据库。”

对应内容:
“如果有人反复请求一个根本不存在的商品 ID,缓存里不会命中,每次都会穿透到数据库。大量这类不存在的数据请求会让数据库压力暴增,这就是缓存穿透。”

  1. 你们如何避免缓存穿透?

骨架:
“缓存空值 + 参数校验 + 合理的短 TTL。”

对应内容:
“我采用三层防御:第一,在接口层对参数做合法性校验,非法 ID 直接拦截;第二,对查不到的数据缓存一个空对象,并设置短 TTL;第三,通过日志监控异常高频的非法 ID 访问,进一步排查是否攻击行为。”

  1. 缓存雪崩是什么?

骨架:
“大量 key 在同一时间失效,导致瞬时流量全部打到数据库。”

对应内容:
“如果很多缓存都设了相同的 TTL,又在同一时间集中过期,那么所有请求都会落到数据库,可能直接把数据库压垮,这种情况就叫缓存雪崩。”

  1. 如何避免缓存雪崩?

骨架:
“给不同 key 加随机过期时间,避免集中同时失效。”

对应内容:
“我在设置缓存 TTL 时,会额外加一个随机值,比如 600s + 随机 0~120s,让 key 的过期时间分散开,不会在同一时间点全部失效,从而避免瞬时流量直接打到数据库。”

  1. 缓存击穿是什么?

骨架:
“热点 key 过期那一瞬间,大量请求同时落到数据库。”

对应内容:
“比如一个超高频访问的分类商品列表,所有请求都依赖这个 key。一旦它刚好过期,大量流量会在同一时间绕过缓存打到数据库,这就是缓存击穿。”

  1. 如何避免缓存击穿?

骨架:
“热点 key 加互斥锁或提前续期,让请求不会同时打到数据库。”

对应内容:
“常见做法是给热点 key 加一个互斥锁,比如用 Redis SETNX,只允许一个线程去构建缓存,其它线程等锁释放后读新的缓存;或者对热点 key 采用逻辑过期,在访问即将过期时后台异步续期,避免高峰期突然过期。”

  1. Redis 用的哪种数据结构?

骨架:
“列表类数据用 String 存 JSON,简单、易维护。”

对应内容:
“我主要用的是 String 类型,把商品列表序列化成 JSON 存进去。这样读取方便、结构清晰,也符合大多数高并发读取的场景,不需要用到复杂结构。”

  1. 你用到的 Redis 操作有哪些?

骨架:
“查、存、删,是最常用的三类。”

对应内容:
“我主要用的是 getsetdel,另外结合 Spring 的 Cache 体系,还用到了 @Cacheable@CacheEvict 做注解式缓存,减少手写 Redis 操作的代码量。”

  1. Redis 崩了怎么办?(简单回答)

骨架:
“保持服务可用,降级到数据库查询。”

对应内容:
“我们默认把缓存设计成‘可用但不依赖’,Redis 挂掉时接口依然能查数据库,只是响应稍慢;同时通过监控尽快恢复 Redis。核心原则是:缓存挂了不能影响主流程,系统必须还能跑。”

四、商品模块与订单的联动(轻度问)

  1. 订单创建前为什么要校验商品?

骨架:
“确保商品有效、可买,避免下单成功但商品状态不对。”

对应内容:
“订单创建前必须核对商品是否存在、是否上架、库存是否足够,否则会造成下单成功、后续流程却走不通的情况,所以要先对商品做完整校验。”

  1. 你校验了哪些字段?

骨架:
“校验存在性、状态、库存、价格是否正常。”

对应内容:
“我主要校验了商品 ID 是否有效、商品是否上架、库存是否大于 0、价格字段是否为正数、是否有异常修改。这些校验能保证订单创建的基础数据是可靠的。”

  1. 校验失败怎么处理?

骨架:
“抛业务异常,阻止下单,给前端明确提示。”

对应内容:
“如果出现商品不存在、下架、库存不足等情况,我会抛出自定义的业务异常,由全局异常处理器拦截并返回固定的错误码和友好提示,让前端明确知道订单无法创建的原因。”

  1. 商品状态对下单有什么影响?

骨架:
“只允许上架状态才能下单,下架或停售都必须禁止。”

对应内容:
“如果商品处于下架、删除、审核中这类状态,我会在订单创建时直接拒绝,防止用户下单成功后无法履约。只有状态为‘上架’的商品才允许进入下一步订单流程。”

  1. 商品价格变动如何处理?(仅概念)

骨架:
“下单时以数据库最新价格为准,不能完全信任前端价格。”

对应内容:
“下单发起时我会重新查数据库里的商品价格,防止前端传旧价或恶意改价;如果价格有变动,要么直接以最新价计算,要么提示用户价格变动后再确认,不允许用旧价格下单。”

  1. 订单查询商品信息的流程是怎样的?

骨架:
“先查订单,再按商品 ID 批量查询商品信息。”

对应内容:
“订单记录里通常只保存商品 ID、数量、单价这些字段。如果要展示订单详情,我会先查订单表,再用商品 ID 去查商品表获取标题、封面图等展示信息,最终组装成订单详情返回前端。”

五、外卖后台项目(二项目常规问 · 完整重写版)

  1. 你负责的模块有哪些?

骨架:
“整个后端都是我一个人从零写的,用来练 Spring Boot 的开发流程。”

对应内容:
“包括分类、菜品、购物车、订单、登录鉴权、参数校验、异常处理、统一响应结构、SQL 编写等全部模块都是我自己实现的,没有团队分工,就是按后台系统全流程练熟 Spring Boot 与 MyBatis 的编码方式。”

  1. 菜品管理和商品管理有哪些不同?

骨架:
“菜品偏展示组合,商品偏库存与销售逻辑。”

对应内容:
“菜品一般会有口味、图片展示等内容,主要用于前台列表展示;商品则更强调库存、上下架、价格、缓存一致性这些销售逻辑。外卖项目的菜品逻辑比商城商品更轻一些,侧重点不同。”

  1. 分类与菜品的关系怎么设计?

骨架:
“一对多,分类是父表,菜品依赖分类 id。”

对应内容:
“我用两张表:分类表(category),菜品表(dish)。菜品表里有 category_id 外键。这样查询、统计和筛选都非常直观,也符合大多数后台系统的设计方式。”

  1. 购物车流程是什么?

骨架:
“新增、增量、查询、删除四步。”

对应内容:
“加购物车时先查当前用户是否已有这道菜;没有则新增,有则数量 +1;查询购物车按用户 ID 返回;下单后清空该用户购物车。所有 SQL 都是我用 MyBatis 手写的,整个流程用事务保证一致性。”

  1. 下单流程你了解吗?

骨架:
“校验 -> 建订单主表 -> 写订单明细 -> 清购物车。”

对应内容:
“我在下单时先校验菜品状态和价格,然后生成订单主表,再批量写入订单明细表,最后清空当前用户的购物车。所有流程都按真实业务逻辑写的,数据库操作都自己用 MyBatis 写 SQL。”

  1. 订单查询按什么条件筛选?

骨架:
“用户维度和时间维度。”

对应内容:
“我做的是按用户 ID 查自己的订单记录,结合下单时间、订单状态做筛选,比如待支付、已完成,也可以按时间倒序排序。”

  1. JWT 登录流程是什么?

骨架:
“登录成功后发 token,后续请求带 token 校验。”

对应内容:
“我用 JWT 做登录鉴权,账号密码校验成功后生成 token,token 里放用户 ID;前端把 token 放在请求头,后端用拦截器解析 token,注入当前用户信息,整个过程不用 session。”

  1. token 里存了什么?

骨架:
“用户标识和基本上下文,不放敏感信息。”

对应内容:
“主要存的是用户 ID 和基本登录时间,不存密码、不存权限敏感字段。后端通过用户 ID 再查数据库得到完整信息。”

  1. token 过期后会发生什么?

骨架:
“后端解析失败,直接拒绝请求。”

对应内容:
“token 过期后拦截器解析会失败,我会抛出未登录异常,由全局异常处理器返回统一的未登录提示,前端跳转到登录页面。”

  1. Spring Cache 怎么使用?

骨架:
“加注解自动缓存,让缓存逻辑更轻量。”

对应内容:
“我在部分非核心但可缓存的接口上用 @Cacheable、@CacheEvict 做缓存处理,Spring Cache 帮我完成 key 管理、序列化和存取,减少手写 Redis 的代码量。”

  1. Spring Cache 和手写 Redis 有什么区别?

骨架:
“Spring Cache 更自动、抽象高;手写 Redis 更灵活、可控强。”

对应内容:
“Spring Cache 用注解就能完成缓存的读写、key 生成和序列化,适合简单场景;手写 Redis 则需要自己写 get/set/del 和 key 设计,但好处是行为完全可控,比如缓存一致性策略、随机 TTL、防击穿逻辑这些,Spring Cache 做不了,只能手写。两个我都用过,场景不同。”

  1. 菜品分类缓存是什么时候清理的?

骨架:
“分类或菜品变更时主动清理,不靠过期时间。”

对应内容:
“在菜品新增、修改、状态变更、分类变更这些写操作之后,我会根据分类 ID 主动删除对应的缓存 key,比如 dish:category:{id}。下一次查询会自动重建缓存。这样比单纯 TTL 更可靠,能保证前端看到的是最新数据。”

  1. 如何避免缓存脏读?

骨架:
“写操作优先更新数据库,再删除或更新缓存。”

对应内容:
“我遵循‘先更新数据库、再删除缓存’的原则。这样不会出现先写缓存后写库导致的数据不一致。对于列表类数据我采用删缓存方式,让下一次请求重新构建最新值,从根本上避免脏读。”

  1. 前后端联调遇到哪些问题?

骨架:
“字段不一致、参数格式不对、状态值不匹配、URL 或方法写错。”

对应内容:
“联调时常见问题包括:前端字段名和后端 DTO 对不上;数字型字段传字符串导致条件匹配不到;状态字段前后端枚举不一致;URL、请求方式、参数放错位置(如 GET 写成 POST);我一般通过打印入参、校验 SQL、用 Postman 重现请求来定位问题。”

  1. 你们的统一响应结构是什么样的?

骨架:
“固定三段:状态码、提示信息、数据体。”

对应内容:
“我定义了一个通用的 Result 类,包含 codemsgdata。所有接口返回统一结构,比如成功时用 Result.success(data),失败用 Result.error(msg)。这样前端解析一致,后端也能统一处理异常和日志,排查问题更稳定。”

六、Nginx 与部署(必问基础)

  1. 你们为什么使用 Nginx?

骨架:
“Nginx 负责转发请求、做静态资源服务,比后端直接暴露端口更稳定。”

对应内容:
“我们用 Nginx 做反向代理,把前端资源和后端接口统一由 Nginx 接入口管理。它稳定、性能好,还能做负载均衡、跨域配置和静态资源托管,比直接把后端暴露出来更安全、可控。”

  1. 反向代理的作用是什么?

骨架:
“把外部请求转发到内部服务,实现隔离、负载均衡、统一入口。”

对应内容:
“反向代理能让用户永远只访问 Nginx,而不是直接访问后端应用。Nginx 根据路径把请求转发到不同服务,比如 /api 转后端端口,/ 返回前端页面。这样可以隐藏内部服务、做集中配置,还能随时换后端端口不影响前端。”

  1. 静态资源怎么处理?

骨架:
“直接由 Nginx 返回,不经过后端。”

对应内容:
“前端打包后的静态资源(HTML、JS、CSS、图片)我会配置到 Nginx 的静态目录,比如 /usr/share/nginx/html。访问页面时 Nginx 直接读取本地文件返回给浏览器,不会走后端,提高访问速度和吞吐量。”

  1. 前后端分离部署的流程是什么?

骨架:
“前端打包放 Nginx,后端打包成 jar 运行,再用 Nginx 做路由转发。”

对应内容:
“流程是:前端先用打包工具生成 dist 包,放进 Nginx 的静态目录;后端用 Maven 打成 jar,在服务器上用 java -jar 运行;最后用 Nginx 配置静态资源目录和 /api 反向代理到后端端口,这样访问域名就能同时访问前端页面和后端接口。”

七、Spring / Spring Boot(必问基础)

  1. Controller、Service、Mapper 的职责是什么?

骨架:
“分层明确:Controller 接参,Service 处理业务,Mapper 访问数据库。”

对应内容:
“Controller 负责接收请求、参数校验和返回响应;Service 里写业务逻辑、事务、流程控制;Mapper 只做数据库 CRUD 和 SQL 映射。这样职责隔离清楚,方便维护。”

  1. @RestController 和 @Controller 区别?

骨架:
“@RestController 默认返回 JSON,@Controller 返回视图。”

对应内容:
“@RestController = @Controller + @ResponseBody,所有方法直接返回 JSON;而 @Controller 用于页面跳转,需要手动加 @ResponseBody 才能返回 JSON。我们后端接口基本都用 @RestController。”

  1. @Autowired 原理?

骨架:
“依赖注入,由 Spring 容器根据类型找到 Bean 并注入。”

对应内容:
“@Autowired 会让 Spring 在容器里按类型查找对应的 Bean,然后注入到属性或构造方法中。本质是 IOC(控制反转)机制,让我们不需要自己 new 对象,而由容器统一管理依赖关系。”

  1. Bean 的生命周期简单描述?

骨架:
“创建 → 初始化 → 使用 → 销毁。”

对应内容:
“Spring 会先实例化 Bean(调用构造方法),然后做依赖注入,再执行初始化方法(如 @PostConstruct),进入可用阶段;容器关闭时调用销毁方法(如 @PreDestroy)。整个过程都由 Spring 容器管理。”

  1. Spring Boot 的自动配置是什么?

骨架:
“按条件自动装配 Bean,让我们不用写大量 XML 或配置。”

对应内容:
“Spring Boot 会根据 classpath 下的依赖、配置文件内容和条件注解(如 @Conditional)自动创建需要的 Bean,比如数据源、MVC 组件、消息转换器等。它通过 spring.factories 加载自动配置类,大幅减少手写配置。”

  1. 配置文件 application.yml 是怎么覆盖的?

骨架:
“优先级由外到内,外部参数会覆盖内部配置。”

对应内容:
“Spring Boot 会按优先级加载配置:命令行参数 > 环境变量 > application.yml > application.properties > 默认配置。比如你用 --server.port=8082 启动,它会覆盖 yml 里的端口。原则就是越外层、越显式的配置优先级越高。”

  1. Spring MVC 的执行流程?

骨架:
“请求进入 DispatcherServlet → 找映射 → 调用 Controller → 返回视图或 JSON。”

对应内容:
“具体流程是:请求先到 DispatcherServlet,它通过 HandlerMapping 找到目标 Controller 方法 → 调用 HandlerAdapter 执行该方法 → 返回结果给 ViewResolver 或消息转换器 → 输出 JSON 或页面。整个流程都在 MVC 体系内自动完成。”

  1. 拦截器的作用是什么?

骨架:
“在 Controller 前后做预处理或收尾处理。”

对应内容:
“拦截器可以在请求进入 Controller 前做登录校验、token 校验、日志记录等,也可以在方法执行后做一些清理操作。它基于 Spring MVC,可拿到请求对象,适合做业务相关的逻辑。”

  1. 过滤器和拦截器区别?

骨架:
“过滤器在 Servlet 层,拦截器在 Spring MVC 层。”

对应内容:
“过滤器是 Java Web 规范,作用范围更靠前,可以拦截所有请求,包括静态资源;拦截器是 Spring 提供的,只能拦截进入 Spring MVC 的请求。过滤器更底层、偏技术处理;拦截器更高层、偏业务处理。”

  1. AOP 了解吗?

骨架:
“用切面在方法执行前后织入额外逻辑,不影响原代码。”

对应内容:
“AOP 可以在不改动业务代码的情况下添加日志、权限校验、耗时统计这样的横切逻辑,比如我写过一个执行时间统计切面,使用 @Around 拦截 Controller 或 Service 方法,记录方法耗时,用于排查性能问题。”

八、MyBatis-Plus(必问基础)

  1. 分页查询怎么写?

骨架:
“用 Page 对象配合 MP 的分页方法即可。”

对应内容:
“我创建 Page<T> 对象,传入 page 和 pageSize,然后调用 mapper.selectPage(pageObj, wrapper)。MP 会自动生成 limit 语句并把分页信息封装在 page 对象里。”

  1. LambdaQueryWrapper 会哪些方法?

骨架:
“eq、like、between、orderBy 都会,用于条件拼接。”

对应内容:
“我常用的有:eqnelikebetweengeleorderByDescorderByAscinisNullisNotNull 等,把条件按‘非空再追加’的方式统一写在 wrapper 里,避免手写 SQL。”

  1. UpdateWrapper 使用过吗?

骨架:
“可以不依赖实体对象,按条件更新指定字段。”

对应内容:
“我用在局部字段更新场景,比如根据商品 ID 把状态字段改成上架或下架,用 UpdateWrapperseteq,无需构造完整实体对象,适合精准更新。”

  1. @TableId 有哪些类型?

骨架:
“自增、雪花、UUID、手动输入。”

对应内容:
“常见的有:AUTO(数据库自增)、ASSIGN_ID(MP 自带雪花算法)、ASSIGN_UUID(生成 UUID)、INPUT(手动传入)。不同项目按主键策略选择不同类型。”

  1. @TableField 有什么用?

骨架:
“字段映射,用来控制表中字段与实体的关系。”

对应内容:
“可以指定数据库字段名、是否参与查询、是否存在于表里,比如 @TableField(exist = false) 用于不在表中的临时字段。还能控制插入、更新策略。”

  1. 自增 id 和雪花算法区别?

骨架:
“自增依赖数据库,雪花算法分布式可生成全局唯一键。”

对应内容:
“自增 ID 由数据库维护,简单但不适合集群;雪花算法由服务端生成,不依赖数据库,分布式场景中可以保证唯一性,也不会有自增瓶颈。”

  1. Mapper 接口的原理?

骨架:
“接口被 MP 动态代理,方法自动绑定 XML 或内置 SQL。”

对应内容:
“Mapper 并没有实现类,MP 在启动时为它创建动态代理对象,把接口方法与 SQL 映射起来。调用 mapper 方法时,MP 会根据方法名、泛型、主键策略去执行相应的 SQL,这就是它能帮我们简化大量代码的原因。”

九、MySQL(基础但必问)

  1. 表结构怎么设计?

骨架:
“按业务拆表,字段保持原子性,必要字段加索引。”

对应内容:
“我会把强关联的业务拆成独立的表,比如商品、分类、订单,用外键或 ID 做关联;字段保持最小颗粒度,不做多值字段;对高频查询字段加普通索引或联合索引,让查询性能稳定。”

  1. 为什么加这几个字段?

骨架:
“为查询、展示、扩展和审计考虑。”

对应内容:
“比如状态字段用于过滤上下架,创建时间和修改时间用于排序和日志追踪,分类 ID 用来做关联查询。每个字段都和实际业务需求对应,不是随便加的。”

  1. 索引是什么?

骨架:
“索引是让查询更快的结构,本质像书的目录。”

对应内容:
“它是 MySQL 为了加速查询构建的 B+ 树结构,通过索引能快速定位数据行,而不需要全表扫描。”

  1. 什么时候走索引?

骨架:
“在条件能命中索引列、数据量大时就会走索引。”

对应内容:
“比如查询包含 where id = ?where username = ?order by indexed_field 这种情况都会使用索引;数据量达到几万以上,会显著提升查询速度。”

  1. 哪些情况索引失效?

骨架:
“对索引列做运算、函数、模糊前置百分号、类型不一致等都会失效。”

对应内容:
“比如 where price + 1 = ?where date(create_time)like '%abc'、字符串字段用数字比较、联合索引不按从左到右使用,这些都会导致无法利用索引而回到全表扫描。”

  1. 左模糊、右模糊哪个走索引?

骨架:
“右模糊能走,左模糊不能走。”

对应内容:
like 'abc%' 能利用前缀匹配走索引;
like '%abc' 会导致无法定位前缀,因此会触发全表扫描,索引失效。”

  1. limit 分页为什么可能变慢?

骨架:
“偏移量越大,需要跳过越多记录,导致扫描量变大。”

对应内容:
“比如 limit 100000, 20,数据库必须先扫描 10 万条再返回 20 条,越往后越慢。大型分页通常用主键或条件分页优化,不直接靠 offset。”

  1. 数据库死锁是什么?(浅问)

骨架:
“两条事务互相持有对方需要的锁,导致都无法继续。”

对应内容:
“比如事务 A 锁了数据 1 等数据 2;事务 B 锁了数据 2 等数据 1,这样彼此等待就形成了死锁。数据库会自动回滚其中一个事务来解除死锁。”

  1. 事务的 4 大特性?

骨架:
“原子性、一致性、隔离性、持久性。”

对应内容:
“原子性确保一个事务要么全部成功要么全部失败;一致性保证数据前后状态有效;隔离性保证多个事务互不干扰;持久性确保提交的数据不会丢失。”

十、Java 基础(最常问 )

  1. 重写和重载的区别?

骨架:
“重写改逻辑,重载改参数。”

对应内容:
“重写是子类改父类的方法实现,方法名和参数都必须一样;重载是在同一个类里方法名相同,但参数类型、数量不同,用于提供不同的调用方式。”

  1. == 和 equals 区别?

骨架:
“== 比较地址,equals 比较内容。”

对应内容:
“== 对引用类型比较的是内存地址是否相同;equals 默认也是地址比较,但像 String、Integer 这些类重写了 equals,因此 equals 比较内容值是否相同。”

  1. HashMap 底层结构?

骨架:
“数组 + 链表 + 红黑树。”

对应内容:
“HashMap 底层用数组保存桶,每个桶上挂链表;当链表过长(默认超过 8),会自动转成红黑树,提升查找效率。存取数据时通过 hash 算法定位桶,再在桶内匹配 key。”

  1. ArrayList 和 LinkedList 区别?

骨架:
“一个用数组,一个用链表;一个查得快,一个增删快。”

对应内容:
“ArrayList 底层是数组,随机访问快,但插入删除需要移动元素;LinkedList 是双向链表,适合频繁插入删除,但随机访问慢。一般情况下都用 ArrayList。”

  1. String 为什么不可变?

骨架:
“设计成不可变是为了安全、省内存、线程安全。”

对应内容:
“String 底层用 final 修饰的字符数组,不允许修改。不可变可以让字符串常量池复用对象、避免被外部代码修改、提升多线程访问的安全性,这也是 String 在 Java 中很基础的设计。”

  1. 什么是接口?什么是抽象类?

骨架:
“接口定义规范,抽象类定义部分实现。”

对应内容:
“接口只有方法规范,让实现类自己完成逻辑;抽象类可以有普通方法和成员变量,能提供一部分默认实现。接口强调能力,抽象类强调模板结构,两者都不能直接实例化。”

  1. 运行时异常 vs 编译时异常?

骨架:
“运行时异常不强制处理,编译时异常必须处理。”

对应内容:
“运行时异常(如 NullPointerException)在运行阶段出现,代码可以不写 try-catch;编译时异常(如 IOException)编译器会强制你处理,要么捕获要么 throws,不处理代码过不了编译。”

  1. 垃圾回收是什么?(基本概念)

骨架:
“自动清理不再使用的对象释放内存。”

对应内容:
“Java 的垃圾回收器会自动监测哪些对象已经不可达,然后回收它们占的内存空间,不需要程序员手动释放,减少内存泄漏,但也会带来一定的停顿和开销。”

  1. final 修饰变量有什么作用?

骨架:
“final 让变量只能赋值一次。”

对应内容:
“final 修饰基本类型时值不能变;修饰引用类型时引用地址不能变,但对象内部状态可以改。final 多用于常量、线程安全、不可变对象这些场景。”

  1. try-catch-finally 执行顺序?

骨架:
“先执行 try,有异常进 catch,最后一定执行 finally。”

对应内容:
“正常情况下先跑 try 块;如果抛异常就进入 catch;finally 无论是否抛异常都会执行,除非遇到系统退出。即便 try 或 catch 有 return,finally 也会在 return 之前执行。”

好,主子,我继续按你现在这套“骨架一句 + 内容一句”的精悍风格,把 97~100 直接砍给你。
这些是工程化 + 排查能力的核心,答得好会让你比其他培训生显得更“像在公司待过”。

十一、工程化与排查能力

  1. 你如何排查一个 500 错误?

骨架:
“先看日志定位异常,再复现请求,最后查数据库或业务逻辑。”

对应内容:
“500 一般是代码异常,我会先看后端日志的堆栈,确定是空指针、类型转换、SQL 执行失败还是参数问题。然后用 Postman 重放同样的请求,看是参数错、字段不一致还是逻辑分支没处理。必要时打印 SQL 在数据库里单独跑,逐层排清是控制层、service 还是 mapper 出的问题。”

  1. 日志你怎么打的?

骨架:
“关键节点打印、错误打堆栈、不要在循环里打日志。”

对应内容:
“我用 slf4j 打日志,请求入口、关键入参、SQL 条件、重要业务分支都会打 info;异常统一由全局异常处理器捕获并打印完整堆栈;避免在循环和高频接口里疯狂打印,保持日志可读。这样出了问题能直观定位字段和流程。”

  1. 本地调试一般怎么做?

骨架:
“加断点、单步执行、配合日志和本地 Postman 复现。”

对应内容:
“我会在关键方法里打断点,用 IDEA 的 debug 模式看入参、局部变量、SQL 参数是否正确;调试接口时用 Postman 或 curl 发请求复现场景;遇到链路长的情况,就在每一层都检查传参是否按预期变化,逐层缩小范围。”

  1. 你怎么看待“可观测性”?

骨架:
“把系统运行状态看得见,才能稳定地维护。”

对应内容:
“可观测性就是通过日志、监控、链路追踪等方式,把系统行为暴露出来,让开发能知道系统哪里慢、哪里错、哪里异常。我在自己的项目里虽然规模小,但也会通过统一日志、异常处理、SQL 打印,让排查问题不靠猜,而靠数据和链路。”

十二、微服务与 Nacos(了解层面)

  1. 你如何理解单体拆分成微服务的原则?
  2. Nacos 在项目中承担什么角色?注册流程如何?
  3. 如果服务实例下线,Nacos 如何感知并通知调用方?
  4. 你会如何使用 Nacos 配置中心管理多环境配置?
  5. 服务调用失败时,有没有考虑限流、熔断或降级思路?

评论