面灵AI→

卓望全栈开发技术面:AI Coding 追问、MySQL、Redis 与前端异步

轮次
技术面
时间
2026-10
来源
牛客网

《面试题目》

一、自我介绍与 AI Coding

  1. 请做一下自我介绍。
  2. 你的个人网站基本上都是通过 AI Coding 完成的吗?
  3. AI 生成的代码,你是怎么验证正确性的?
  4. 除了测试前端交互和后端接口,还有没有其他验证方式?
  5. 在 AI 开始编码之前,你会不会检查它给出的技术设计是否合理?
  6. 有没有使用过 Skills 或者其他工具,减少 AI 生成代码时的幻觉和错误?
  7. 假设 AI 修改了一个功能,并告诉你代码和单元测试都通过了,你怎么进一步确认它的结果是可信的?
  8. 如果 AI 修改代码之后,单元测试反而失败了,你会怎么处理?

二、设计模式

  1. 你的数据同步框架使用了模板方法模式,除此之外还了解哪些设计模式?
  2. 能不能举一个适合使用策略模式的实际业务场景?

三、MySQL 大数据量查询优化

  1. 假设一张流水表有 1 亿条数据,现在只需要查询最近一天的数据,你会从哪些方面优化 SQL 查询?
  2. 除了索引优化、覆盖索引、分区分表等方案,还有没有其他优化思路?

四、Redis 缓存一致性

  1. 在更新数据时,采用先更新数据库、再删除缓存的方案,能否保证数据最终一致性?
  2. 延迟双删的具体执行流程是什么?

五、敏感数据存储

  1. 密码、身份证号码等敏感信息,在数据库中应该如何安全存储?
  2. 如果密码采用加盐哈希存储,用户登录时如何进行密码校验?
  3. 身份证号码和用户密码可以采用相同的存储方案吗?

六、前端异步请求场景

  1. 搜索框输入 “ja” 时发送一次请求,继续输入 “java” 又发送一次请求;如果 “java” 的响应先返回、“ja” 的响应后返回,如何确保页面最终展示的是 “java” 的搜索结果?
  2. 前端如何取消上一次尚未完成的网络请求?
  3. 除了取消请求,还有没有其他方式避免旧请求覆盖新请求的结果?

七、Linux 日志排查

  1. 如果日志文件非常大,如何快速查看最新的一部分日志?
  2. 如何持续实时查看新增日志?
  3. 如果已经知道一个 requestId,如何筛选该请求对应的日志?

八、Java 基础

  1. JDK 8 默认使用什么垃圾回收器?
  2. Java 中的 final 关键字有什么作用?为什么需要 final?
  3. final 修饰集合后,还能不能添加或者删除元素?
  4. final 修饰对象引用后,还能不能修改对象内部的属性?

九、AI 基础与 Python

  1. 平时使用过哪些 AI Coding 工具?
  2. 除了 AI 辅助编程,对 Agent、深度学习、RAG 等 AI 相关技术了解多少?
  3. Python 中的 GIL 是什么?能不能进一步解释它的作用?
  4. Python 中的装饰器了解吗?
  5. Python 中的生成器和迭代器有什么区别?

十、反问环节

  1. 岗位具体使用什么前后端技术栈?
  2. 校招生入职后有没有导师培养机制?是否会直接参与实际项目?
  3. 从本次面试表现来看,还有哪些能力需要继续提升?
  4. 后续还有哪些面试流程?

《参考解析》

AI Coding:考的是你的验收能力,不是你会不会用工具

「AI 写的代码你怎么验证」是这一轮追问最细的地方,答案要能说出一条完整的验证链:先读 diff 看它有没有偏离事先确认的设计,再盯接口契约和边界(空值、异常、并发、事务),然后跑单测,再做端到端的手工验证,最后交出去之后看日志和监控。单测通过远不等于可信——AI 写的测试常常和实现同源、断言偏弱(只断言「不抛异常」)、或者把真正出问题的那一段 mock 掉了,所以「AI 说测试全绿」之后至少要补三问:测试是谁写的、覆盖到哪些分支、断言够不够强。AI 改完代码单测反而挂了,先分辨是测试过时(行为契约确实变了,测试该改)还是实现引入了 bug,判断依据是需求与接口契约,不是哪边改起来便宜;实在分不清就把改动缩到最小重跑,绝不能为了让测试变绿去放宽断言。

减少幻觉靠的是流程而不是某个工具:把项目约定、目录结构和相关文件喂进上下文(只给相关文件,别整仓塞进去),要求它先读再写、先给设计方案再动手,接口签名、数据结构和影响面先跟自己核对一遍;用 lint、typecheck、测试当硬闸门,小步提交便于回滚。编码前审设计这一步不要跳过——方案错了,代码写得再漂亮都是返工,这也是面试官想听到的「人在环路里的位置」。

场景题三连:亿级流水查询、缓存一致性、敏感数据存储

1 亿条流水表只查最近一天,第一顺位是按天分区(或按时间范围分表),让查询落到单个分区,避免全表扫描;索引要能同时命中时间范围和过滤条件,字段尽量做成覆盖索引避免回表,只 select 需要的列并加 limit;写法上用时间区间比较,别把时间列包在函数里(date(created_at)=... 会直接让索引失效);再往上就是预聚合与分层——近期数据留热表、历史数据归档到冷表或数仓,按天/按小时预汇总成统计表,大结果集翻页别用深 offset,读多写少的场景再考虑只读副本。如果这类查询是分析型的,换 ClickHouse / Doris 这类列存比在 MySQL 上硬扛更划算。

「先更新数据库再删缓存」在无并发读的情况下能收敛,但它不是强一致:读请求可能在删除前读到旧值并回填缓存、删除本身可能失败、主从延迟也会留下脏数据。延迟双删就是补这个窗口——更新数据库、删一次缓存,等一小段时间(要大于一次「读旧值 + 回填」的耗时,通常按几百毫秒估)再删一次,把并发回填的旧值清掉;代价是延迟不好精确估、逻辑也没那么好维护。更常用的加固是给缓存设 TTL 兜底、删除失败进重试队列,或者干脆用 binlog 订阅(Canal)异步删缓存,把一致性问题从业务代码里挪出去。

敏感数据要分类型处理。密码坚决不做可逆加密,用带盐的慢哈希(bcrypt / scrypt / Argon2),每个用户一个随机盐,盐和算法参数一起存进库里;校验时取出盐和哈希,用同一算法重算再恒定时间比较,全程不还原明文。身份证号不一样:它既需要校验、又常被要求回显和检索,所以走对称加密(如 AES-GCM)并把密钥交给 KMS 管理,需要等值查询时另存一列 HMAC 或哈希,展示时脱敏,同时配上访问审计和最小权限。两者存储方案不能互换——把身份证做成哈希就查不了,把密码做成可逆加密等于没加密。

前端请求竞态与 Linux 日志排查

「java 的响应先回、ja 的响应后回」是典型竞态,标准解法有三条:一是取消,fetch 用 AbortController(保存上一次的 controller,新请求发起前 abort 掉),axios 走 AbortController 或拦截器;二是丢弃,给每次请求打一个自增序号或时间戳,回调里只接受序号最大的那一次结果,或者只接受和当前输入框内容匹配的那个响应;三是减少请求,用防抖让它别每敲一个字符就发一次。取消并不总是来得及(服务端可能已经在处理、某些库也不支持中断),所以实践中「防抖 + 序号校验」是最稳的组合,取消只是省流量和省后端压力。第三条是根本判据,前两条是事后补救,答题时把「为什么取消不够」讲出来,深度就够了。

日志排查是最基础的动手题:看最新一段用 tail -n 200 app.log,实时跟进用 tail -f(日志会轮转就用 tail -F);大文件不要 cat,用 less +G、grep -n 拿到行号再跳过去;实时过滤用 tail -f app.log | grep --line-buffered requestId 或 rg;已经知道 requestId 就直接 grep requestId app.log,多文件用 grep -rn,压缩归档用 zgrep,JSON 格式的日志配上 jq 按字段筛。真正的加分项是在回答里带出「日志要能按 traceId 串起整条链路」——这决定了排查是几分钟还是几小时,也是面试官在意的工程习惯。

Java、Python 基础与这一轮在筛什么

JDK 8 的默认收集器是 Parallel Scavenge + Parallel Old(即 Parallel GC),设计目标是吞吐量;G1 从 JDK 9 起才成为默认,JDK 8 里可以用 -XX:+UseG1GC 手动开启。final 有三个位置:修饰变量表示不可再赋值(引用不可变,但对象内部的属性照样能改)、修饰方法表示不能被子类重写、修饰类表示不能被继承;它的价值在于表达不可变意图、保护契约不被子类破坏,并配合 JMM 的 final 语义保证对象安全发布。所以 final 修饰集合后元素仍可增删,要真正不可变得用 Collections.unmodifiableList 或 List.of 包装一层。

Python 的 GIL 是 CPython 的全局解释器锁,同一进程同一时刻只有一个线程在执行字节码,作用是保护引用计数这类解释器内部状态、让实现简单。结果是 CPU 密集型的多线程拿不到并行加速,但 IO 密集仍然有效(IO 等待时会释放 GIL),要并行就上多进程、C 扩展或 numpy 这类会在计算时释放 GIL 的库。装饰器是接收函数并返回函数的高阶函数,用来挂日志、计时、鉴权、缓存这类横切逻辑,本质是 f = decorator(f),带参数的装饰器多一层闭包,记得用 functools.wraps 保住原函数的元信息。生成器和迭代器的关系是:迭代器实现 __iter__ / __next__ 协议,生成器是造迭代器的语法糖(含 yield 的函数、生成器表达式),惰性求值、省内存、能暂停恢复,代价是只能消费一次。

这一轮的风格是广而浅:AI Coding 反复追问「你怎么确认它对」,后端三道场景题都要求讲权衡,前端和 Linux 考的是日常动手能力,Java 与 Python 只到基础概念。全栈岗尤其看知识面能不能自洽,准备时把简历上每个关键词准备到能往下讲两层,比背八股收益高得多。作者最后提到结果待通知——面试末尾问「还有哪些能力需要提升」是很好的复盘切入点,面试官的回答往往就是这个岗位真实的评价维度。