面灵AI→

恒生电子面经-恒生电子后端开发岗面经-01

轮次
面试合集
时间
2026-10
来源
牛客网

《面试题目》

(面经 01)

  1. 你在实习时候遇到的困难
  2. 怎么解决 AI 幻觉,举例子
  3. 分布式事务的实现
  4. Spring Boot 注解的作用
  5. @Autowired 和 @Resource 的区别
  6. 事务什么时候使用,作用是什么
  7. 文件系统批量读,一个文件到达之后进行高效写,有 200 个线程,其中一个是兜底线程要最后执行,怎么保证兜底线程在最后执行?
  8. 数据库 MySQL 多表连接有几种方式
  9. 多表查询,7、8 张表连表查询怎么提高查询性能

(面经 02) 10. 选一个项目,介绍一下你认为做的最好的功能,是怎么实现的,实现思路是怎么样的 11. 如果说你用 C 去写一个通信库,你认为怎么写才能让这个库最高效运行 12. TCP 了解吗,讲一讲 13. TCP 的三次握手是怎么做的呢,ACK 起到什么作用呢 14. 你有用过 Linux 吗,是否熟悉常见命令 15. 进程和线程了解吗,进程和线程的通信是如何实现的 16. 你提到你用 AI 协作开发,你怎么确保 AI 写的代码没有问题呢 17. 小项目中或许可以,但是如果是在大的工程项目中,或许每个部分都是好的,组合链接起来就出错了,你该如何去排查呢

(面经 03) 18. 介绍 final 关键字 19. 哪些框架用了反射 20. 用过哪些中间件 21. 怎样实现分布式锁 22. 什么时候用到分布式锁 23. Spring 掌握的怎么样 24. AOP 的实现方式 25. HTTPS 的加密传输过程 26. 数据库熟悉哪种 27. SQL 慢查询 28. 有接触过 AI 编程吗

(面经 04) 29. 接口和抽象类的区别 30. 说说 JUC 并发包下你了解的类和工具 31. final 关键字作用在变量、方法、类上分别是什么效果,引用类型要注意什么 32. 项目中用过哪些中间件 33. @Transactional 事务的传播属性有哪些 34. 讲讲对 Spring IOC 的理解,DI 有哪些注入方式 35. MySQL 有哪几种事务隔离级别 36. InnoDB 和 MyISAM 存储引擎区别 37. 怎么看待手写代码和 AI 辅助编程

(面经 05) 38. 操作系统这门课有哪些记忆点? 39. 进程与线程的区别? 40. Transformer 架构理解 + 应用心得,AI 对于技术架构选型的实际应用经验 41. 有本地部署过吗,本地参数调优经验 42. Token 怎么计算? 43. 大模型幻觉是什么?怎么解决? 44. 高并发本地生活项目防超卖的整体链路 45. 实际工作中方案决策冲突怎么和同事解决?

(面经 06) 46. 重试和幂等的策略是怎么设计的? 47. 怎么应对大批量的并发资源申请的? 48. QPS 是多少?为什么不用 Redis? 49. Java 的 HashMap 底层实现?是不是线程安全的? 50. String、StringBuilder、StringBuffer 的区别 51. 优化 SQL 的几个角度 52. 分库分表的概念,以及怎么实现

(面经 07) 53. 介绍一下项目一,解决什么问题 54. 项目一问了一下同一个订单怎么防止重复取消 55. 介绍一下项目二,解决什么问题

(面经 08) 56. 系统访问数组具体流程,vector 和 list 原理以及适用场景 57. 有没有用过树,有哪些树,说一下红黑树原理 58. 有没有用过指针,操作时会出现哪些问题怎么解决,这里我引出智能指针,分别说 unique_ptr、shared_ptr 以及 weak_ptr 原理以及使用场景 59. 知道哪些排序算法,说一下快排的逻辑原理 60. 有没有用过 AI,用过哪些,一般用在什么地方 61. C 和 C++ 的区别 62. 线程和进程的区别

(面经 09) 63. 有没有过考研考公经历还是说一直就在准备找工作 64. 你对于工作行业和公司首先关注的点有哪些? 65. 你认为你对 C/C++ 语言掌握的怎么样 66. 全局变量和局部变量有什么区别 67. 什么是内存泄露?你就这么避免内存泄露? 68. MySQL 的内联外联左联右联是什么? 69. 什么是视图?

《参考解析》

@Autowired 与 @Resource 的区别

@Autowired 是 Spring 自己的注解,默认按类型(byType)注入,同类型有多个候选时才退化为按字段名匹配,可用 @Qualifier 或 @Primary 精确指定;它只有 required 一个属性,required=false 表示允许注入不到。@Resource 是 JSR-250 标准注解,默认按名字(byName)注入,名字取自字段名或 setter 名,找不到同名 bean 才按类型兜底,还支持 name、type 两个属性。工程上的差别是:@Resource 不绑定 Spring 容器、便于替换实现;@Autowired 能用在构造器上并配合 Lombok 的 @RequiredArgsConstructor,而 @Resource 不能标在构造器上。字段注入虽然省事,但会让依赖不可变性和「启动即暴露循环依赖」这两个好处落空,生产代码更推荐构造器注入。

分布式事务的实现

分布式事务要解决的是跨库、跨服务的一次业务操作要么全成、要么全败,以及中间态是否可见。四类主流方案:① XA 两阶段提交,协调者统一 prepare/commit,强一致但同步阻塞、行锁持有时间长,只适合低频强一致场景;② TCC,业务自己实现 Try-Confirm-Cancel,把资源冻结在业务层而不是数据库行锁上,性能优于 XA 但侵入大,必须处理空回滚、悬挂、幂等三个坑;③ 本地消息表或事务消息,把「改本地数据」和「发消息」放进同一个本地事务,再由定时任务或 MQ 投递重试,达到最终一致,是最常用的落地方式;④ Saga,把长事务拆成一串本地事务加补偿动作,适合流程长、允许中间态的业务。选型后必须配幂等(唯一键或去重表)、重试上限和对账补偿,否则最终一致只是口号。

AI 幻觉的成因与工程化治理

幻觉的根因是模型做的是下一个 token 的概率预测而不是事实查证,所以知识边界外、时效性强、要求精确数字或引用的地方最容易编。治理分三层:输入层用 RAG 把资料放进上下文,并明确要求「仅依据资料回答,资料没有就说不知道」,同时做查询改写与权限过滤,从源头压缩自由发挥的空间;生成层降温、要求结构化输出并带出处(引用片段 ID),对关键字段做 schema 校验,让编造的内容在格式上就暴露;校验层把答案与召回片段做一致性核对,对金额、日期、法规条文这类高风险字段走规则或二次模型核验,拿不准就降级成「建议人工确认」。工程上还要有评测集和埋点,量化幻觉率而不是靠感觉——比如我曾遇到模型编出不存在的接口名,改成交互式工具调用并要求参数从工具列表里选之后该问题消失。

Spring 事务的传播行为与失效场景

传播行为共 7 种,至少要能区分 REQUIRED(默认,有则加入、无则新建)、REQUIRES_NEW(挂起当前事务另开一个,适合「主流程回滚也要留痕」的日志)、NESTED(用保存点嵌套,内层回滚不影响外层)以及 SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER。事务失效的高频原因:方法不是 public(CGLIB 代理拦截不到)、同类内部方法自调用(没走代理,要靠 AopContext.currentProxy() 或拆类)、异常被 catch 吞掉、抛的是受检异常而默认只回滚 RuntimeException 与 Error(需显式 rollbackFor)、类没被 Spring 管理或用 final/static 方法、以及子线程拿不到同一个事务上下文。另外要说清「什么时候该用事务」:一组写操作必须原子时才用,长事务会长时间持有连接和行锁,必须拆短。

保证兜底线程最后执行

这是线程协同题,前提是 200 个业务线程处理分片文件,兜底线程负责汇总或收尾,必须等其余全部结束。可用的手段:① CountDownLatch 最直白,计数设为业务线程数,业务线程在 finally 里 countDown,兜底线程 await 归零后再执行;② CyclicBarrier 或 Phaser,适合分阶段推进或多批循环的场景,Phaser 还支持动态注册;③ CompletableFuture.allOf(…).thenRun(兜底),组合式写法最干净,异常也能聚合;④ 线程池加 AtomicInteger 计数,归零时触发。坑有三个:兜底逻辑必须幂等(重复触发不能重复汇总)、countDown 必须放 finally 否则 latch 永远不归零、不要用 join() 逐个等待把并发变成串行。如果要求「200 个线程里就有一个是兜底线程」,要用 latch 预占一个线程,避免兜底任务排在队列尾被业务任务饿死。

多表连接与多表 JOIN 的性能优化

MySQL 的连接类型有内连接(INNER JOIN 或逗号写法)、外连接(LEFT/RIGHT OUTER JOIN)、交叉连接(CROSS JOIN,笛卡尔积)和自连接;MySQL 没有 FULL OUTER JOIN,要用 LEFT JOIN 与 RIGHT JOIN 做 UNION 模拟。7、8 张表连查的优化按优先级:① 减少参与连接的数据量,先用子查询或 CTE 把每张表过滤到最小集再连接,把条件下推到最内层,避免先笛卡尔积再过滤;② 保证连接列有索引且两侧类型、字符集、排序规则完全一致(不一致会触发隐式转换导致索引失效),被驱动表(EXPLAIN 里 type=ALL 的那张)的连接列必须有索引,这是 nested loop join 能否收敛的关键;③ 控制连接顺序,小结果集驱动大表,表多了优化器容易选错计划,必要时用 STRAIGHT_JOIN 或拆成两步;④ 结构层面,能冗余高频字段就冗余,把一条 8 表 JOIN 换成应用层两三次简单查询加内存拼装,通常更快也更好维护,再加缓存或宽表。看 EXPLAIN 的 rows 乘积与 Extra 里的 Using join buffer,就能定位是哪一步炸了。

分布式锁的实现与选型

用在多实例部署下需要串行化同一份资源的地方,比如扣库存、发券、生成唯一单号、定时任务只让一个节点跑,而这些是数据库行锁或本地锁覆盖不到的。实现有三类:① Redis 的 SET key value NX PX ttl 保证加锁原子,释放时用 Lua 校验 value 是自己的再删以免误删他人锁,更稳的做法是 Redisson 的看门狗自动续期加可重入;② ZooKeeper 临时顺序节点,会话断开自动释放、天然公平,一致性由 ZAB 保证,代价是性能与运维成本;③ 数据库唯一键或 SELECT … FOR UPDATE,实现简单但性能差、易死锁,只适合低频场景。加分点在于讨论细节:key 的粒度按业务维度加资源 ID 设计、超时时间要大于业务耗时的 P99 或改用续期、自旋重试要有上限、以及 Redlock 在时钟漂移与主从切换下不保证强一致的争议;一致性要求极高时要配 fencing token,把锁的版本号带到下游写入,让过期持有者的写被拒掉。

AOP 的实现方式与动态代理

AOP 按织入时机分三类:编译期(AspectJ 的 ajc)、类加载期(LTW,需要 javaagent)、运行期动态代理,Spring AOP 只走第三类。两种代理实现要能对比:JDK 动态代理基于接口,用 Proxy 加 InvocationHandler 生成实现同一批接口的代理类,所以拿不到实现类的类型;CGLIB 基于继承生成子类并覆写方法,因此 final 类、final 与 private 方法代理不了,还要注意构造器会被调用两次这类坑。Spring Boot 2.x 之后默认 proxyTargetClass=true,一律优先 CGLIB。概念要串得起来:切点 Pointcut 定义在哪拦(注解、包路径、方法签名),通知 Advice 定义拦下来做什么(@Before、@AfterReturning、@AfterThrowing、@Around),两者合成切面 Aspect,再由 Advisor 与 ProxyFactory 生成代理对象放进容器。要能指出自我调用失效、事务与缓存注解都建立在这套机制上,以及 @Around 里必须保证继续 proceed 否则整条链路断掉。

final 关键字与 JUC 并发工具

final 用在不同位置语义不同:修饰变量时基本类型值不可改、引用类型引用不可改但对象内容可以改(最常被追问的点);修饰方法时不能被子类覆写;修饰类时不能被继承,String、Integer 都是这种。还有一条容易被忽略的语义:正确构造完成后(构造器里没有 this 逸出),其他线程一定看得到 final 字段的写值,这是 JMM 给的安全发布保证,也是不可变对象能免同步共享的原因——而普通字段没有这个保证,要靠 volatile 或加锁。JUC 按用途报菜名:原子类(AtomicInteger、LongAdder 在高竞争下分段累加优于 CAS 自旋)、锁(ReentrantLock、ReadWriteLock、StampedLock)、同步器(CountDownLatch、CyclicBarrier、Semaphore、Phaser)、并发容器(ConcurrentHashMap、CopyOnWriteArrayList、阻塞队列家族)、线程池(ThreadPoolExecutor、ForkJoinPool)与 CompletableFuture 编排。能说清 AQS 的 state 加 CLH 等待队列是 ReentrantLock、Semaphore、CountDownLatch 的共同底座,比单纯列名字值钱。

MySQL 隔离级别与存储引擎差异

四种隔离级别:读未提交会脏读;读已提交(Oracle 默认)解决脏读但仍有不可重复读;可重复读是 MySQL 默认,MVCC 快照读保证同一事务内读到的行不变,配合间隙锁在很大程度上避免幻读;串行化加锁读、性能最差。可补一句 RC 与 RR 在复制上的差别:RC 配 statement 格式的 binlog 会造成主从不一致,RR 才安全,所以线上要改 RC 必须确认 binlog_format=row。InnoDB 与 MyISAM 的对比:InnoDB 支持事务与崩溃恢复(redo log)、行级锁与 MVCC、外键,主键是聚簇索引(数据按主键组织,二级索引存主键值需要回表);MyISAM 只有表锁、没有事务,索引与数据分离(非聚簇),count(*) 靠存的行数很快,全文索引曾是它的优势。现在默认选 InnoDB,只有纯只读归档场景才可能考虑 MyISAM。

慢 SQL 优化与分库分表

先定位再优化:开慢查询日志并设 long_query_time、看 performance_schema 的 TOP SQL、结合监控里的耗时分布,再用 EXPLAIN 看 type、key、rows 与 Extra,出现 ALL、Using filesort、Using temporary 就是重点。优化角度分五层:① 索引,按最左前缀建联合索引、范围条件放最后、用覆盖索引消回表,注意函数与隐式类型转换导致失效;② SQL 写法,避免 select *、子查询改 join、大 IN 改 join 或分批、深分页用游标或延迟关联;③ 表结构,字段类型选小、冷热字段拆表、大字段单独存;④ 架构,读写分离、加缓存、检索类查询交给 ES,最后才是分库分表;⑤ 业务,限流、异步化、批量合并、实时统计改离线预聚合。分库分表是最后手段,垂直按业务域拆、水平按分片键(用户 ID 或时间)拆,分片键选错会导致大量跨片查询且最难返工;配套必须解决全局唯一 ID(雪花、号段、Redis INCR)、跨片分页聚合、跨片事务的最终一致,以及成倍扩容加双写迁移的在线方案。

TCP 三次握手、HTTPS 与进程线程通信

三次握手:客户端发 SYN(带随机初始序号 seq=x)进入 SYN_SENT;服务端回 SYN+ACK(seq=y,ack=x+1)进入 SYN_RCVD;客户端再回 ACK(ack=y+1),双方进入 ESTABLISHED。为什么不是两次:服务端需要客户端的这次确认,才能确定「自己的包对方收到了」,同时避免历史失效的连接请求突然到达而白白建立连接;ACK 的作用就是告知「我已收到你的 SYN,且我期望的下一个字节序号是 x+1」。HTTPS 在 TCP 连接后先做 TLS 握手:客户端发 ClientHello(版本、密码套件、随机数),服务端回 ServerHello 与证书链;客户端用内置 CA 公钥验签并校验证书域名、有效期与吊销状态;主流的 ECDHE 交换下服务端私钥只用于签名,因而具备前向安全;双方由共享的 pre-master 与两个随机数派生出会话密钥,之后用对称加密(如 AES-GCM)传输数据并校验完整性。进程与线程通信:进程间靠管道、消息队列、共享内存(最快但要自己做同步)、信号量、信号与 socket;线程间共享地址空间,靠锁、条件变量与无锁结构——ThreadLocal 是线程私有副本而非通信手段,线程池复用下会串数据,用完必须 remove。