上周刚从厦门回来一口气面了两家公司的Java后端岗位。趁记忆还热乎把这次的面试总结整理出来。如果你也在看厦门的后端机会或者正准备约面试这篇复盘应该能给你一些参考。两家公司一家是跨境ERP自研另一家做本地生活类SaaS面试风格完全不一样一家上来就是笔试加三轮深挖另一家先给机试再聊业务和系统设计。两天面试下来最大的感受是厦门的技术岗虽然不像一线城市那么卷但面试官对基础深度和项目真实性的追问一点不含糊。这篇文章不写虚的只把我在面试中遇到的题目、回答思路、踩过的坑全部摊开讲。1. 为什么把这次厦门面试单独写一篇复盘1.1 先看厦门后端岗位的真实行情厦门的技术岗位数量肯定比不了北上广深但也不至于冷清。本地叫得上名号的主要集中在几个方向跨境电商和外贸SaaS厦门做跨境电商的圈子很成熟、本地生活服务、政务信息化、游戏公司以及一部分制造业数字化转型。薪资范围大致是3到5年经验的Java后端月薪普遍在13k到22k之间如果是核心项目或者技术负责人候选能到25k以上。不过厦门有一个明显特点好公司就那么几十家网络上的面经很少如果只盯着大厂投递容易错过本地口碑不错的自研团队。我在筛选机会时重点看两类公司一是业务稳定、技术团队有自研深度的二是业务虽小但系统链路完整、能学到东西的。这次选的两家正好分别代表这两种情况所以放在一起复盘对比性很强。1.2 两家公司的选样逻辑第一家下文叫A公司是跨境电商ERP系统核心业务是给卖家和物流商做库存、订单、仓储中转发货管理。这类系统对数据的实时性和一致性要求极高尤其是多仓、多平台的库存同步非常考验后端工程师对分布式事务和并发控制的功底。第二家B公司是本地生活SaaS主要服务餐饮门店提供点餐、收银、会员和供应链管理。产品形态偏企业级应用技术栈里有消息队列、定时任务、小程序接入业务模型比ERP更偏交易和促销。选这两家的原因是业务场景互补一个偏供应链和库存一致性一个偏订单和支付交易。面试复盘时可以把两条线对照来看比单独记录某一家的问题更有参考价值。2. 第一家A公司复盘跨境ERP的并发和事务细节2.1 岗位JD和面试准备方向A公司给的岗位是Java高级开发工程师JD里反复出现几个关键词订单同步、库存扣减、多租户隔离、MQ削峰。面试前我重点准备了分布式锁和乐观锁在库存系统里的应用以及MySQL在较高写入量下的表结构设计事后证明这些几乎全部被问到。面试流程是到公司先做一套40分钟的技术笔试题接着两轮技术面试最后HR面。整体节奏紧凑面试官看得出来是有多年后端经验的老人不会对着简历逐字问而是拿业务场景来考你。2.2 笔试环节基础题和开放题的混合笔试大概是8道题前6道是基础题后2道是设计题。基础题里有几道值得说一道问“MySQL的InnoDB在RR隔离级别下怎么避免幻读”除了回答MVCC和间隙锁我特意补充了当前读和一致性读的区别面试官在后面的技术面里果然顺着这个点往下问。还有一道是“Redis做分布式锁需要注意什么”这个属于高频题。我按自己的项目经验分了三个层次回答setnx加过期时间的基础用法设置唯一value是为了防误删最后提到续期和RedLock的争论。设计题是“如果一个新订单积压导致库存扣减频繁失败你会怎么优化”这里不能只答“加缓存”我把库存拆成数据库扣减和Redis预扣两条路径并且说明了对账Job怎么处理最终一致性。这道题我现在回想起来核心是考察你有没有真实处理过超卖问题。A公司面试官在后续追问中直接问如果Redis宕机了订单还能不能继续很多人第一反应是降级但他们更希望听到“库存扣减请求失败后要走本地消息表/输出日志由对账系统恢复”这是ERP场景里很现实的做法。2.3 一轮技术面项目深挖和“为什么”连问一轮面试的主要风格是顺着你的项目经历不断问“为什么”。我讲了一个多平台订单拉取和库存同步的模块面试官连问了几个问题为什么用定时任务拉订单而不是监听Webhook这里其实有两个陷阱一是平台方Webhook可能不稳定二是响应太慢需要回查定时任务可以自己控制频率但要注意增量游标存储和失败重试的幂等性。接着问库存同步为什么选MySQL悲观锁而不是乐观锁。我说单行库存更新用UPDATE加条件库存数0更高效不需要锁等待但高并发下会出现大量更新失败所以线采用了Redis预扣MySQL异步落账的方案。面试官点头后又追问了一句预扣和实扣的差值怎么处理我回答用定时对账任务把Redis扣减记录和数据库流水比对排查出因为退款、取消导致的差额然后生成差异调整单。这里我踩了一个坑提到对账任务时我说的是“每分钟跑一次”面试官立刻问如果对账数据量大每分钟全量扫描是不是太浪费正确思路是只增量扫描最近5分钟的流水并且用分片参数控制扫描范围而不是粗暴地全表查。2.4 二轮技术面分布式事务场景和系统设计边界二轮面试更像系统设计讨论。面试官给了一个具体场景卖家在ERP后台改库存同时前端小店正在下单怎么保证不改超卖这个问题的本质是“并发写同一个库存Key”我对高并发写路径和数据最终一致性做了拆分写库存操作走接口网关先校验操作类型落在Redis中使用Lua脚本原子更新当前库存Key同时发送MQ消息给MySQL消费者异步写入库存流水表消费者需要做幂等用“业务单号仓库编码SKU编码”作为唯一键查询侧直接读Redis缓存不回源数据库。面试官追问了一个细节Lua脚本里如果库存扣减到负数怎么处理我回答脚本内先读取当前值若扣减后小于0则返回失败码并向上层抛异常如果允许负库存预售需要另外引入预占库存字段和生产安全库存概念。这轮我最大的反思是回答系统设计题时“边界感”很重要。我一度想把MQ、Redis、分库分表全部塞进方案里面试官提醒说要先看你在这个岗位要解决的问题有多大。如果是单仓库存MySQL加乐观锁就够了根本不值得引入Redis。所以设计答辩时应该先搞清楚数据量级和并发量级再决定要不要上中间件。2.5 A公司HR面业务稳定性与加班节奏A公司HR面比较直接问了上一份工作离职原因、薪资流水、期望涨幅也介绍了公司目前的业务增长情况。因为跨境电商受外部环境影响会有波动HR特别强调了“业务稳定”和“团队还在扩编”但这个说法我保持保留态度还得结合offer阶段的信息综合判断。这个环节我一点心得不要做过多承诺也不要抱怨上家把离职原因往“个人成长和业务方向变化”上靠最稳妥。3. 第二家B公司复盘本地生活SaaS的业务与技术混合面试3.1 公司和岗位的初印象B公司做餐饮SaaS客户群体是连锁快餐和茶饮品牌。产品包含门店收银、小程序点餐、后厨KDS、会员储值对后端来说非常典型订单状态机复杂、支付回调要幂等、门店网络可能抖动导致离线消息堆积。面试流程是先约机试在线编程限时1小时通过后到公司进行技术组长面业务总监面。机试题目不算难但很考代码习惯这个下面细说。3.2 机试环节订单状态机模块设计机试题目实现一个订单状态流转的核心类支持创建、支付、取消、退款、完成等操作要求状态非法转移能抛出异常并且要支持并发场景下防止重复提交。这道题考查重点不是LeetCode算法而是状态机建模和并发控制能力。我当时写了一个状态枚举类用Map配置合法流转路径然后在状态变更方法上使用synchronized或者数据库乐观锁控制并发。不过机试结束后我意识到最佳实践应该是先把“状态机表”设计出来订单表带status字段和version字段更新时用UPDATE ... WHERE status ? AND version ? 的方式保证CAS同时把操作流水记录到单独表里避免不加区分地在内存里加锁。因为门店点餐场景可能同时有多个终端操作同一订单跨进程锁是必要的。注意机试不是只跑通就行面试官会看整个工程结构比如有没有把状态流转逻辑放在Entity层、有没有吞掉异常、有没有打印日志。我这次在这一步做得好的是把无效状态转移封装成业务异常而不是返回false这让调用方能区分“参数错误”和“系统故障”。3.3 技术组长面从支付回调聊到幂等边界技术组长面问得比较细第一个问题是“微信支付回调怎么保证幂等”。按常见标准答案回答回调中先根据支付单号查本地订单如果订单已经是已支付状态则直接返回成功给微信如果状态为待支付则执行支付确认逻辑并通过数据库唯一约束和事务控制并发。组长继续问如果支付回调到了但本地订单已经因为超时被关闭了怎么办这是我在实际项目中遇到过的坑。绝对不能直接拒绝回调正确流程是先把订单状态从关闭反转为待支付或者生成一张支付成功凭证然后再走发货流程。我之前踩过这个坑所以回答时把场景分成了“支付单先通知后查单”和“本地状态异常”两种组长表示认可。接着问“门店断网场景下怎么处理点餐请求”。我回答离线模式收银端本地缓存菜单和菜品下单先写本地数据库网络恢复后再推送到云端推送接口需要有batchId和幂等处理。组长补充了一个点订单编号需要包含门店编号、日期和序列号拼接时要注意跨天和时间回拨不能只依赖System.currentTimeMillis()。3.4 业务总监面清单式场景题和取舍能力业务总监面很有意思几乎不问代码问了一个餐厅会员储值的业务题目顾客充值100送20退款时怎么计算可退余额这类问题看起来简单但业务语义很重。不能用“退款当前余额”一刀切因为赠款部分和本金部分比例不同。正确做法是记录充值流水按比例或者按时间顺序抵扣本金和赠送金额并处理退货规则。总监想听的其实是工程师能不能理解业务规则并把规则翻译成状态机和流水账。紧接着问“如果全国几千家门店同时上线秒杀活动后端怎么预防超卖”这个问题和A公司库存问题很像但也有差异餐饮秒杀的商品库存通常只在单店维度所以最好先用门店维度的Redis锁或本地锁再落数据库。不能直接用全局锁否则不同门店互相阻塞吞吐量完全不可接受。这个场景答案很考验你有没有实际做过按租户/门店维度的隔离设计。3.5 B公司面试的整体感受B公司面试给我的感觉是“业务思维优先”。技术题都是为了解决业务问题而存在的面试官不太喜欢炫技式回答更关注你能不能把规则落地成可靠代码。另外B公司的面试节奏比A公司温和机试后到现场面试时也给了充足的提问时间。我建议如果约了类似本地生活服务公司的面试一定要提前熟悉订单生命周期、支付回调、门店维度的数据隔离这三个是命中率极高的方向。4. 两家公司的面试侧写与厦门求职对比4.1 面试流程和考察重心的对照用表格来对比最直观对比项A公司跨境ERPB公司本地生活SaaS面试环节笔试两轮技术面HR面机试组长面总监面技术侧重分布式事务、库存并发、Redis订单状态机、支付幂等、门店隔离项目提问风格连环追问“为什么”业务场景化提问重规则理解最看重的品质基础扎实系统设计边界感业务建模能力兜底设计开放题常见类型库存扣减、对账、中间件选型充值退款、秒杀、断网补偿这个表不是标准答案但它能帮助你快速判断公司的文化和技术偏好。A公司内部明显有较多自研中间件和后台任务系统面试官在意你能否在复杂链路里找到一致性保障手段。B公司更偏工程化产品面试官在意的是你在真实业务约束下能不能把规则代码化。4.2 技术栈和能力模型差异A公司使用了较多的自研框架中间件也铺得比较满考的是“你怎么扛住高并发写”。B公司更关注业务领域建模考的是“你怎么让一套通用系统适配不同门店的差异”。没有高下之分只是选择标准不同。从个人发展来看如果你想深耕高并发、分布式系统A类公司更有练手机会如果将来想走技术管理或者做业务中台B类公司能积累更多业务领域知识。在厦门这个市场里两类公司都有稳定的需求关键是不要拿一线大厂的标准来套所有公司否则很容易觉得“哪里都差一点”。4.3 在厦门找工作的几个实用建议厦门面试机会不算多一次跳槽窗口期可能只约到三四家所以每轮面试都要做详细复盘。我习惯按“题面—我当时回答—参考答案—错因分析”四栏记录面试结束后立刻整理否则三天后细节就模糊了。还有一点很重要多确认候选公司的业务收入来源和团队规模厦门的公司存在不少“业务重心在外地、厦门只是研发分部”的情况。如果研发团队不满10人就要认真评估独立成长空间和运维压力不要只看title。最后谈薪时厦门公司普遍没有股票期权那一套更多是固定14薪或年终奖所以要把月基数和年终比例问清楚再换算成总包对比。5. 面试通用避坑实录5.1 简历项目描述别只写“实现了什么”这是我这次面试最大的教训。A公司面试官直接说你这行“负责订单模块开发”等于什么都没说。正确的写法要包含业务背景、技术方案、个人承担的量化结果比如“设计并实现多平台订单统一拉取模块将订单同步延迟从5分钟降到30秒内接口成功率提升至99.95%”。每个项目留两到三个能被深挖的技术点面试官才会顺着简历问你想被问到的问题。5.2 手撕代码时最容易忽略的三种边界机试和笔试的代码题不要求高级算法但边界处理非常加分。第一是空指针和空集合所有从外部接口拿到的对象都要判空不要信任下游返回。第二是并发场景下的重复提交能用唯一索引兜底的就不要只靠代码判断。第三是时间戳字段的时区问题订单跨天、统计跨天都要明确定义用哪个时区尤其是跨境ERP场景。简单来说编码时把“如果这里失败了会怎样”想一遍代码质量会提升一截。5.3 谈薪与背调阶段要留的证据两家公司都要求提供薪资流水这很常见但沟通时要有底线不要只关注月薪要问清绩效工资占比、加班费算法、五险一金基数。厦门很多中小公司的公积金基数可能不是全额工资这一块差距算下来一年可能有一两万块值得花时间问清楚。背调环节如果HR要联系方式尽量提供前领导而不是关系一般的同事并且提前和对方打招呼。我一般会把项目产出和离职时间整理成一段文字发给证明人既能帮助对方准确回答也能避免信息不一致导致的offer延误。写在最后面完两家公司我最深的一个体会是面试总结不是把题目抄一遍而是要回到“岗位需要解决什么问题”的视角去重新组织自己的知识体系。A公司让我重新审视自己对分布式事务的理解B公司让我意识到业务规则建模同样重要。这两个方向在厦门都有对应的招人需求关键是你能不能用项目经验证明自己真的解决过类似问题。最后分享一个小技巧每次面试完把答得不好的点按“下次再遇到该怎么答”写成一段话放在手机备忘录里。连续两三次面试后你会发现那些常见的系统设计题是有固定套路的先问边界和量级再选方案最后谈兜底。掌握这个节奏后面的面试会越面越稳。