顺丰 Java 线下二面面经
- 轮次
- 二面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 实习经历深入交流:上下游之间怎么通信,调接口还是发 MQ?
- 流量有多大,太大了会有什么措施?
- 怎么保证幂等?
- 你发现数据库压力很大、很慢,怎么缓解?
- 有没有想过系统怎么优化,让数据库压力小一点?
- 索引:a 和 b 联合索引,和 b 和 a 联合索引,同样条件 a=1,有没有什么情况下反而会用 b-a 不用 a-b?
- 如果 select 的是 count(*) 和 * 有什么区别?
- 如果 count(*) 且 a=1,b 是
%name,会走 a-b 索引吗? - 平常怎么用 AI?什么时候人工需要介入?
《参考解析》
- 上下游通信方式怎么选:同步调接口适合强依赖、要立刻拿结果且能接受下游故障传导的场景;发 MQ 适合弱依赖、可异步、能接受最终一致的场景,代价是要额外处理消息丢失、重复和顺序。回答时最好说清自己项目里这条链路属于哪一类,以及为什么当时没有选另一种。
- 幂等的落地方式:核心是「同一个业务请求重复到达,结果只生效一次」。常见做法有唯一业务键 + 数据库唯一索引(最容易保证,代价是要处理冲突返回)、Redis 的
SETNX占位(快但要注意锁续期和误删)、状态机 + 条件更新(update ... where status = '待支付'靠影响行数判断是否抢到)、以及消息表去重。幂等键要由调用方生成并在重试时保持不变,否则重试本身就会造出第二条记录。 - 数据库压力大怎么缓解:先定位是慢 SQL、锁等待还是连接数打满,别一上来就上缓存。读侧可以加缓存、读写分离、把复杂聚合下推到数据库用一次条件聚合代替多次查询;写侧可以批量提交、异步化、按分片键拆表。索引层面要确认高频查询有没有覆盖索引、有没有因为函数或隐式类型转换导致索引失效。真正有效的是先量化——打开慢查询日志拿 top SQL,再按收益排序改。
- 联合索引 (a,b) 与 (b,a) 的选择:在只有
a=1的条件下,(a,b)能直接用 a 做前缀定位,(b,a)理论上要先扫 b 的有序区间。但优化器是成本驱动的:如果 a 的选择性极差(比如只有几个取值)、或者查询要返回的列正好被(b,a)覆盖,走(b,a)做覆盖索引扫描反而可能比走(a,b)再回表更便宜。所以「一定走 a-b」是错的,最终要看EXPLAIN的估算行数和访问方式。 count(*)与count(列)的区别:count(*)只统计行数,不需要判断列是否为 NULL,InnoDB 会挑最小的可用二级索引来扫;count(具体列)要额外判断该列是否非空,无法走同样的优化路径,列上没索引时更慢。语义上两者在列可能为 NULL 时结果不同。a = 1 and b like '%name'会不会走 (a,b):会用到(a,b)索引,但只能用到 a 这一段——%name是前导通配符,无法利用索引的有序性做范围定位,b 上只能回表过滤。如果查询字段能被(a,b)覆盖,就退化成「用 a 定位 + 索引内过滤」;否则会变成大量回表,优化器可能直接放弃索引走全表扫描。前面加固定的前缀(like 'name%')才能让 b 段也参与索引定位。- 什么时候人工介入 AI:把 AI 当第一稿生产者,人负责判断「对不对」和「要不要」。涉及线上数据变更、权限、金额、对外发布这类不可逆动作时必须人工确认;AI 给出的结论缺乏可核查的出处时也要人工接手。判断标准可以简化成一条:出错之后的代价能不能承受。