Java高频面试题:03
接口幂等性怎么设计
仅靠前端生成 token + 后端 Redis 先查后删的接口幂等方案,在高频场景下会导致业务失败且用户无法重试的严重问题。
常见方案缺陷:模拟网游点卡抢购场景,请求 A 删除 token 后因数据库异常业务失败,用户重试的请求 B 因 token 不存在被判定重复提交,导致无法下单。
优化方案:将 Redis 中的 token 改为带 status 的 hash 结构(初始 unused),用 Lua 脚本保证原子操作:判断状态为 unused 则改为 processing 执行业务,完成后改为 done;重复请求时 processing 状态提示等待,done 状态返回结果。
兜底方案:Redis 失效时,通过数据库唯一索引(如用户 ID + 请求 ID)实现幂等,插入成功执行业务,主键冲突则拦截重复请求。
视频建议面试时按缺陷、优化、兜底三层逻辑回答,以体现处理生产环境问题的经验。
LIMIT 100000000 10和LIMIT 10哪个快?
视频讲解了 MySQL 分页的性能差异及深度分页的优化方案。
分页性能对比:视频明确 LIMIT 10 比 LIMIT 100000000 10 更快。因为 MySQL 采用分层架构,server 层负责 SQL 解析优化,存储引擎负责数据读写;执行 LIMIT 100000000 10 时,存储引擎需先读取 1 亿条数据并丢弃,再返回后续 10 条,会浪费大量硬盘、CPU 资源,属于深度分页问题。
游标式分页优化:记住上一页最后一条数据的 id,下次查询通过 WHERE id>last_id LIMIT 10 直接取数,轻快高效,适合下拉加载连续翻页,但不支持跳页。
子查询优化:借助二级索引仅查询索引列和主键获取目标 id,再通过主键索引查询全量数据,无需全表扫描回表,数据量小速度快。
搜索引擎优化:可使用 Elasticsearch 处理,但需注意 Elasticsearch 的 from+size 也存在深度分页问题,需改用 scroll 或 search_after 方式。
深度分页的核心问题是大偏移量导致数据库需跳过大量数据,需根据业务场景选择对应优化方案。
你配了熔断器,以为稳了?
视频通过后端面试场景,讲解熔断器的响应时间盲区及微服务防雪崩的三层防御方案。
面试场景还原:面试官询问有三年经验的后端开发者微服务防血崩方案,开发者答用 Hystrix 或 Sentinel 配置失败率触发的熔断器;面试官再设场景,订单服务调用响应变慢的库存服务,因请求未触发失败率熔断阈值,订单服务线程池被占满最终崩溃,开发者无法给出应对方案。
指出核心盲区:视频提出熔断器存在响应时间盲区,慢响应未触发失败率时,会比请求失败更隐蔽地拖垮上游服务。
三层防御方案:第一层设多维度熔断指标,含失败率熔断、慢调用比例熔断、并发数限流;第二层采用线程池隔离,为每个下游服务分配独立线程池,避免慢请求影响其他服务;第三层配置熔断后的降级与恢复策略,含返回默认值、半开状态试探、实时监控告警。
该内容考察开发者从配置工具到设计弹性系统的工程思维。
调用第三方接口需要注意哪些问题?
调用第三方接口需从多维度做好防御性编程以保障系统稳定。
超时与重试:需设置合理超时时间,避免线程被长时间占用;实现重试机制,注意接口幂等性,采用指数退避算法避免加重第三方服务压力。
熔断降级:使用 Hystrix、Sentinel 等组件,第三方接口持续失败或超时自动熔断,快速失败避免请求堆积;熔断后需有降级方案,如返回默认值、用缓存数据等,保障核心业务。
限流流量控制:针对第三方接口调用频率限制,用令牌桶或漏桶算法在客户端做限流,避免触发对方限流策略被封禁。
异常日志处理:捕获网络、超时、业务等所有异常,记录含请求参数、响应结果、耗时、异常信息的详细日志,敏感信息需脱敏。
版本兼容处理:关注第三方接口版本变更通知,代码中做好版本隔离,用适配器模式处理版本差异,对返回字段做空值判断。
安全防护措施:API Key、Secret 等敏感信息不硬编码,存于配置中心或密钥管理系统;用 HTTPS 加密传输,对请求参数签名验证防篡改。
监控告警设置:监控第三方接口调用成功率、响应时间、错误率等指标,设置告警阈值,指标异常时及时通知处理。
掌握这些要点可构建健壮可靠的第三方服务集成系统架构。
你用了seata,以为分布式事务稳了?
面试官通过分布式事务场景题,考察四年后端开发者对 Seata 及分布式事务的深层理解。
Seata AT 模式局限:Seata AT 模式通过代理数据源,在业务 SQL 执行前后记录 UNDO LOG,二阶段提交删日志、回滚时依日志反向补偿;若回滚时数据被其他事务修改,Seata 无法自动覆盖,只能抛出异常,需人工介入,该模式适合并发冲突概率低的业务,不适合秒杀库存等高并发热点场景。
TCC 模式补位方案:TCC 模式由业务方实现 Try-Confirm-Cancel 三个接口,Try 阶段预留资源,Confirm 阶段执行,Cancel 阶段补偿,灵活性更高但开发成本大,适合跨行转账等核心强一致性链路,且 Confirm 和 Cancel 接口需实现幂等设计。
最终一致性兜底:可采用本地消息表,将业务操作与消息写入放同一本地事务,定时扫描推送消息;也可通过对账系统每日跑批比对跨系统数据,还可与产品沟通,接受积分延迟到账等短暂不一致的业务妥协。
这道题核心考察开发者从 “用框架” 到 “懂原理、能兜底” 的工程思维。
10g日志内存,内存只有2g,hashmap直接oom
视频讲解了 10G 日志文件在仅 2G 内存时,找出访问次数最多的前 10 个 IP 的三层处理方案。
哈希分流拆分:对每个 IP 计算哈希值并对机器数取模,将 10G 大文件拆分至对应小文件,确保同一 IP 进入同一小文件;若小文件仍过大,可再次拆分或分发多台机器并行处理,将单文件大小控制在内存可承载范围。
局部堆排取 Top10:将单个小文件读入内存,用 HashMap 统计每个 IP 的出现次数;维护大小为 10 的小顶堆,遍历 HashMap 条目,若当前 IP 次数大于堆顶则替换并调整堆,无需全量排序即可得到该文件的 Top10。
多路归并得全局 Top10:收集所有小文件的局部 Top10,汇总后再次通过堆排序得到全局访问次数最多的前 10 个 IP;若数据量仍大,可先取每个小文件的 Top100,再合并取 Top10。
该方案核心是运用分治思想,解决内存不足时的海量数据处理问题。
说一下Spring Boot的自动原理
视频以工厂搭建场景拆解 Spring Boot 启动核心逻辑,适配 Java 面试需求。
加载基础环境:项目启动入口为启动类的 main 方法,调用 SpringApplication.run 后,先读取项目的 Application.yml、application.properties 配置文件及系统环境变量,获取 server.port、spring.application.name 等基础配置信息。
创建 Spring 容器:Spring 容器负责管理控制器、服务、数据仓库等所有 Bean 对象,开发者可直接从容器获取对象,无需手动实例化。
自动配置机制:Spring Boot 扫描 starter 依赖,按需加载对应自动配置类,如引入 web starter 则加载 WebMvc、内置 Tomcat 的配置;仅当容器无自定义数据源时,默认加载 Hikari 数据源,可省去 90% 繁琐配置。
启动内置服务器:自动配置类初始化内置 Tomcat,监听配置端口并部署项目,容器启动后发布应用就绪事件,项目即可通过配置端口访问。
Spring Boot 启动核心为加载基础环境、创建容器加自动配置、启动内置服务器三步。
MySQL索引有哪些分类?
Java 面试中仅罗列 MySQL 索引常见类型易不被面试官认可。
数据结构维度:含 B + 树索引(默认,擅长范围查询、排序聚合)、哈希索引(等值查询快,不支持范围查询)、倒排索引(用于全文搜索)、R 树索引(用于多维空间数据查询)4 种。
InnoDB 实现维度:分为聚簇索引(即主键索引,叶子节点存完整数据行)、非聚簇索引(叶子节点存索引列和主键值,需回表取全行数据)。
索引性质维度:含普通索引(仅提升查询速度)、主键索引(唯一非空,一个表仅一个)、唯一索引(值不重复,可含多个 NULL)、联合索引(多列组合,需注意列顺序)、全文索引(针对长文本关键词搜索)、空间索引(用于空间数据区域距离查询)。
按三个维度结构化作答,能体现分类思路与底层原理,提升面试表现。
分布式事务有了解吗?跟我讲下不同的事务模式的特性?
视频讲解了 Seata 框架四种分布式事务模式的特性及适用场景。
XA 模式:基于两阶段提交协议,第一阶段事务协调者询问参与者能否提交,第二阶段根据反馈执行提交或回滚;优点是一致性强,缺点是事务过程锁定资源、并发能力低,适合金融转账这类对一致性要求高、并发要求低的场景。
TCC 模式:属于补偿型模式,分为 Try(预留资源)、Confirm(扣减资源)、Cancel(释放资源)三个阶段;性能较高,为最终一致性,适合电商扣减库存这类高并发、可接受短暂不一致的场景。
Seata 模式:将长事务拆分为多个带补偿操作的本地事务,子事务失败时调用补偿回滚;吞吐量高,但异步补偿无法保证硬性执行,适合业务流程长、对执行要求不苛刻的场景,如预定业务。
AT 模式:是 Seata 框架的自动补偿方案,通过记录日志实现失败自动回滚;对业务代码无侵入、使用简单,适合快速接入分布式事务、对一致性要求适中的场景。
这些分布式事务模式的本质是在数据一致性与性能之间做权衡
订单流水号一般根据什么来生成?
视频讲解了订单流水号(分布式 ID 的一种)的核心生成需求与四种常见生成方案。
核心生成需求:订单流水号需满足全局唯一性、含业务信息的可读性、高生成性能、趋势递增、防止篡改(避免暴露业务规模)五个核心要求。
数据库自增方案:分库分表时需用独立表自增 ID,缺点是易暴露业务量,性能受限于数据库。
UUID 方案:工作中一般不使用,原因是无序、可读性差、存储传输效率低。
Redis 原子自增方案:用 INCR 命令生成 ID,性能远高于数据库,但易暴露业务量,可添加日期时间戳优化,需保证 Redis 高可用。
雪花算法方案:当前主流选择,标准雪花算法生成 64 位 long 类型 ID,由符号位、时间戳、机器 ID、序列号组成,性能高、可灵活调整位数分配,但需解决时间回拨、机器 ID 唯一性问题,可参考美团 Leaf 方案的号段模式、雪花模式优化。
其中不推荐UUID因为无序,而redis原子自增和数据库自增容易暴露业务量
