上海某公司后端面试:Spring、消息可靠性与秒杀库存
- base
- 上海
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 如何介绍自己的技术背景,做过哪些项目?
- 项目前端使用了什么技术?
- GET 与 POST 有什么区别?
- 如何设计用户登录状态的判断?
- 用户密码能否以明文保存,应该怎样处理?
- Spring 的核心是什么,怎样理解 IoC 和 DI?
- Spring 与 Spring Boot 有什么区别?
- Bean 有哪些作用域,Spring MVC 中的 Bean 默认是单例吗?
- Bean 的生命周期有哪些主要阶段?
- 常用的两种代理方式是什么?
- AOP 有哪些通知类型?
- 秒杀抢徽章功能怎样保证不会超额发放?
- RabbitMQ 有哪些关键机制,消息怎样从生产者到达消费者?
- 项目中是否遇到消息丢失,怎样定位和解决?
- 为什么在项目里选择 Bitmap?
- 第二个项目怎样在网关实现统一鉴权?
- 常用的 Linux 命令有哪些?
- MySQL 有哪些事务隔离级别?
- 除 MySQL 外,还了解哪些国产数据库?
- Java 常用集合和数据结构有哪些?
- Java 面向对象的三大特性是什么,怎样理解?
- 使用过哪些 Java 版本,了解哪些新特性?
- 编写项目时,辅助编程工具参与了哪些工作,占比如何?
《参考解析》
IoC 讲对象由谁管理,DI 讲依赖怎样交给它
容器负责创建、装配和管理对象,业务对象通过构造器等方式接收依赖,不必在内部把所有依赖都直接创建出来。Spring Boot 在 Spring 的基础上提供自动配置和配套依赖组织等能力,减少常见应用的启动配置工作。
单例是 Spring Bean 的默认作用域,其边界是容器内的一份 Bean 定义。Web 环境还可以使用 request、session 等作用域。Controller 通常也是单例,把某次请求的数据放进可变实例字段会造成并发干扰;方法局部变量与每个请求独立的数据对象更合适。参见 Spring Bean 作用域。
库存判断和扣减要作为一个整体
“先读剩余数量,再单独扣减”会让多个请求同时看到库存充足。使用数据库时,可以把条件写进更新语句,只在库存大于零时扣减,并检查受影响行数。还要为领取记录设置合适的唯一约束,处理同一用户重复点击和请求重试。
如果先在 Redis 预扣,再异步落库,需要说明两边失败时如何恢复一致:预扣成功但消息没有发出、消息重投、落库失败,分别怎样处理。仅仅加一把锁,并不能自动解决这些情况。
消息丢失分发送、存储、消费三段看
生产者确认用于判断消息是否被 RabbitMQ 接收并承担责任,消费者确认则表示消费端已完成相应处理,两者互不替代。业务尚未写入成功就确认消费,会留下处理丢失的窗口;连接故障后的重发又可能形成重复消息,因此消费者必须考虑幂等。参见 RabbitMQ 确认机制。
实际排查可以从一条业务消息的标识出发,依次查看发送记录、路由结果、队列状态和消费结果。持久化、队列副本与失败重试也需要匹配可靠性要求,而不是只看客户端调用有没有抛异常。
Bitmap 适合回答“有没有”
签到、是否领取等二值状态可以映射成一个个 bit,用少量空间表示大量状态。但要先说明用户标识如何映射到位置:编号极度稀疏时,直接把最大用户编号当偏移量会浪费空间。需要保存领取时间、次数或详细记录时,单个 bit 就不够,仍需其他结构配合。
网关认证后,资源权限仍要核对
网关可以统一检查会话或令牌的有效性,并把可信的用户身份传给后端。业务接口仍需判断这个用户是否有权操作当前订单、文件等资源。后端不能直接相信客户端传来的用户编号,也不能让客户端伪造的身份头绕过网关认证。