云计算百科
云计算领域专业知识百科平台

全栈面试实战:从商品详情到可靠下单,如何设计库存扣减链路?

全栈面试实战:从商品详情到可靠下单,如何设计库存扣减链路?

作者:王文峰(神秘小峯 / 山峯)|专注 Java、全栈开发与业务系统实战

全栈面试实战:从商品详情到可靠下单,如何设计库存扣减链路?

  • 全栈面试实战:从商品详情到可靠下单,如何设计库存扣减链路?
    • 一、面试题与业务背景
      • 面试官提问
      • 业务场景
      • 目标与边界
    • 二、先给结论:把正确性放在数据库边界内
    • 三、核心流程拆解
      • 1. 商品详情页:展示价格,但提交时重新校验
      • 2. API 契约:让重试、错误和订单状态可表达
      • 3. 服务端:用条件更新处理并发扣减
      • 4. 事务到底保证什么
      • 5. 支付回调:按状态机和事件幂等处理
    • 四、缓存、消息队列与演进
      • 库存缓存适合做什么
      • 消息队列适合做什么
    • 五、异常场景与验证
    • 六、方案取舍与上线关注点
    • 七、面试官可能继续追问
    • 八、总结
    • 九、把业务问题转化为需求清单
      • 1. 先识别参与者
      • 2. 明确业务对象
      • 3. 功能需求
      • 4. 非功能需求
      • 5. 需求澄清问题
      • 6. 需求与设计的映射
      • 7. 需求优先级
    • 十、端到端架构与模块边界
      • 1. 逻辑组件
      • 2. 单体起步时的边界
      • 3. 请求链路
      • 4. 不同职责不要混在 Controller
      • 5. 同步与异步边界
      • 6. 一致性边界
      • 7. 系统上下文图
      • 8. 容量估算的输入
    • 十一、数据模型深入设计
      • 1. 商品与 SKU
      • 2. 库存按仓库建模
      • 3. 可售库存的定义
      • 4. 库存流水
      • 5. 为什么需要库存流水
      • 6. 订单头与订单明细
      • 7. 金额精度
      • 8. 订单状态字段
      • 9. 软删除与历史数据
      • 10. 索引设计原则
      • 11. 外键取舍
      • 12. 数据迁移策略
    • 十二、Java 服务端分层实现
      • 1. 请求 DTO
      • 2. Controller 示例
      • 3. 输入校验
      • 4. 应用服务
      • 5. 仓储接口
      • 6. MyBatis 更新语句
      • 7. 事务传播与代理
      • 8. 异常映射
      • 9. 订单号生成
      • 10. 幂等冲突处理
    • 十三、价格、优惠与订单金额
      • 1. 价格来源
      • 2. 价格快照
      • 3. 优惠券并发
      • 4. 优惠锁定时机
      • 5. 价格变化时的用户体验
    • 十四、库存策略对比与并发控制
      • 1. 直接扣减
      • 2. 预占库存
      • 3. 条件更新
      • 4. 悲观锁
      • 5. 乐观锁
      • 6. 多 SKU 批量下单
      • 7. 死锁处理
      • 8. 热门 SKU
      • 9. 库存流水与余额核对
      • 10. 库存回补必须幂等
    • 十五、订单状态机与状态迁移
      • 1. 状态定义示例
      • 2. 状态迁移表
      • 3. 状态更新要有前置条件
      • 4. 状态与副作用
      • 5. 状态机测试
    • 十六、取消订单与超时关闭
      • 1. 用户取消
      • 2. 超时任务
      • 3. 条件关闭
      • 4. 批量扫描
      • 5. 支付临界时序
    • 十七、支付适配与回调安全
      • 1. 支付请求流程
      • 2. 回调校验
      • 3. 回调幂等
      • 4. 回调响应时机
      • 5. 主动查询
      • 6. 退款与部分退款
      • 7. 密钥管理
    • 十八、Outbox 与可靠事件发布
      • 1. 问题窗口
      • 2. Outbox 表
      • 3. 写入流程
      • 4. 并发发布器
      • 5. 消费者幂等
      • 6. 消息版本兼容
      • 7. 重试与死信
    • 十九、前端工程实现细节
      • 1. 页面状态建模
      • 2. 幂等键的客户端生命周期
      • 3. 避免重复请求的多层措施
      • 4. 错误展示
      • 5. 可访问性
      • 6. 表单校验
      • 7. 防止跨站请求与令牌泄漏
      • 8. 前端埋点
    • 二十、API 设计与兼容性
      • 1. HTTP 状态码
      • 2. 错误响应结构
      • 3. 订单查询接口
      • 4. 列表分页
      • 5. API 版本
      • 6. 幂等键协议
    • 二十一、安全与隐私
      • 1. 身份认证
      • 2. 授权
      • 3. 输入防护
      • 4. 重放攻击
      • 5. 速率限制
      • 6. 敏感信息
      • 7. 审计日志
      • 8. 权限测试
    • 二十二、测试策略
      • 1. 单元测试
      • 2. Repository 集成测试
      • 3. API 集成测试
      • 4. 契约测试
      • 5. 并发测试
      • 6. 故障注入
      • 7. 属性测试
      • 8. 测试数据管理
      • 9. 压力测试指标
      • 10. 压测结果解释
    • 二十三、可观测性与生产运维
      • 1. 结构化日志字段
      • 2. 关键指标
      • 3. 告警原则
      • 4. 链路追踪
      • 5. 运行手册
      • 6. 数据修复
    • 二十四、部署、灰度与回滚
      • 1. 配置管理
      • 2. 数据库变更顺序
      • 3. 灰度策略
      • 4. 回滚边界
      • 5. 发布后核验
    • 二十五、性能优化的先后顺序
      • 1. 先测量再优化
      • 2. 数据库查询
      • 3. 连接池
      • 4. 缓存商品读取
      • 5. 限流与排队
      • 6. 分区与拆分
    • 二十六、常见错误设计及其修正
      • 错误一:前端计算总价并直接提交
      • 错误二:先查库存再减库存
      • 错误三:按钮禁用就认为请求幂等
      • 错误四:把支付接口放进数据库事务
      • 错误五:支付回调收到就直接改成已支付
      • 错误六:消息只发送一次
      • 错误七:所有异常都无限重试
      • 错误八:为了高并发先上复杂架构
      • 错误九:用订单号难猜代替授权
      • 错误十:只看接口 200,不查业务不变量
    • 二十七、方案演进路线
      • 阶段一:单体与单库
      • 阶段二:异步副作用
      • 阶段三:拆分支付或商品服务
      • 阶段四:热点库存治理
      • 阶段五:多区域能力
    • 二十八、面试回答的组织方式
      • 1. 开场先确认约束
      • 2. 先画核心链路
      • 3. 选择两个重点深入
      • 4. 主动讲失败路径
      • 5. 讲取舍而非背组件
      • 6. 量化验证方法
      • 7. 一分钟回答示例
      • 8. 面试中容易过度承诺的说法
    • 二十九、面试官追问扩展题
      • 1. 如果同一订单有多个 SKU,如何避免部分扣减?
      • 2. 如果订单和库存分属不同数据库怎么办?
      • 3. 幂等键保存多久?
      • 4. 相同幂等键不同请求为什么不能直接返回旧订单?
      • 5. 为什么请求摘要不能包含非确定字段?
      • 6. 如何处理锁等待超时?
      • 7. 订单号生成器故障怎么办?
      • 8. 数据库主从延迟会影响幂等读取吗?
      • 9. 缓存读到库存为零但数据库有货怎么办?
      • 10. 如何避免超时关闭任务重复释放库存?
      • 11. 如何处理支付平台回调乱序?
      • 12. 消息积压时下单接口是否应该失败?
      • 13. 如何确认订单没有丢失?
      • 14. 如果用户重复支付怎么办?
      • 15. 如何防止越权取消订单?
      • 16. 数据库事务隔离级别选什么?
      • 17. 为什么库存检查 SQL 的数量必须校验为正数?
      • 18. 为什么要求库存字段非负约束?
      • 19. 金额比较如何避免精度错误?
      • 20. 怎样处理订单查询的隐私?
    • 三十、示例项目目录与职责
      • 1. API 包
      • 2. Application 包
      • 3. Domain 包
      • 4. Infrastructure 包
      • 5. 测试包
    • 三十一、订单创建伪代码逐步推演
      • 1. 接收请求
      • 2. 规范化请求
      • 3. 查询幂等结果
      • 4. 开启事务
      • 5. 获取服务端报价
      • 6. 占用库存
      • 7. 创建订单快照
      • 8. 写入库存流水
      • 9. 写入 Outbox
      • 10. 提交事务
      • 11. 返回结果
      • 12. 后续副作用
    • 三十二、系统不变量清单
    • 三十三、数据库事务与锁的注意事项
      • 1. 事务长度
      • 2. 锁顺序
      • 3. 隔离级别
      • 4. 唯一约束
      • 5. 自增主键与热点
      • 6. 读写分离
      • 7. 连接超时与事务不确定性
    • 三十四、部署环境和配置检查
      • 1. 环境隔离
      • 2. 超时预算
      • 3. 重试预算
      • 4. 线程池隔离
      • 5. 健康检查
      • 6. 时钟同步
      • 7. 配置验证
    • 三十五、数据保留和归档
      • 1. 业务保留期限
      • 2. 归档前验证
      • 3. 冷热数据分离
      • 4. 删除与隐私请求
      • 5. 归档任务幂等
    • 三十六、不同业务类型下的变化
      • 1. 数字商品
      • 2. 预约服务
      • 3. 票务活动
      • 4. 订阅服务
      • 5. 多仓履约
      • 6. 预售商品
    • 三十七、示例故障演练
      • 演练一:应用在提交后立即退出
      • 演练二:支付回调重复十次
      • 演练三:消息代理不可用
      • 演练四:超时任务重复运行
      • 演练五:数据库主库切换
    • 三十八、文章中的示例限制
    • 三十九、进一步学习和落地清单
      • 业务梳理
      • 设计评审
      • 验证准备
      • 上线准备
    • 四十、最终总结
      • 面向业务
      • 面向前端
      • 面向后端
      • 面向数据
      • 面向架构
      • 面向面试
    • 四十一、创建订单接口的完整时序
      • 时序参与者
      • 正常时序
      • 事务边界解释
      • 时序中的不确定点
    • 四十二、不同失败点的恢复设计
      • 在请求到达网关前失败
      • 网关认证失败
      • 参数校验失败
      • 商品不可售
      • 价格发生变化
      • 库存条件更新失败
      • 订单明细插入失败
      • 唯一约束冲突
      • 事务提交超时
      • 响应序列化失败
      • Outbox 发布失败
    • 四十三、订单查询与状态轮询
      • 查询接口职责
      • 查询响应字段
      • 不返回的字段
      • 轮询策略
      • 长轮询与推送
      • 列表与详情一致性
    • 四十四、接口字段与校验策略明细
      • SKU 标识
      • 数量
      • 幂等键
      • 地址或配送信息
      • 优惠券标识
      • 返回字段
    • 四十五、数据库事务示例推演
      • 正常事务
      • 库存不足事务
      • 订单写入失败事务
      • 幂等冲突事务
      • 事务后支付
      • 事务后发送消息的风险
    • 四十六、库存占用、扣减和释放的语义
      • 方案 A:下单即扣减
      • 方案 B:下单预占,支付后确认
      • 方案 C:支付后再扣减
      • 方案选择问题
    • 四十七、审计与业务时间线
      • 时间线事件
      • 时间线字段
      • 审计与普通日志的区别
      • 人工操作
    • 四十八、重试策略与退避
      • 可重试错误
      • 不应盲目重试的错误
      • 指数退避
      • 重试责任分配
      • 重试可观测性
    • 四十九、限流与过载保护
      • 用户维度
      • SKU 维度
      • 系统维度
      • 限流响应
      • 熔断
      • 舱壁隔离
    • 五十、发布事件的版本化示例
      • 事件基本结构
      • 事件设计原则
      • 事件重复
      • 事件乱序
      • 事件重放
    • 五十一、管理后台与客服工具
      • 订单搜索
      • 订单时间线
      • 失败原因
      • 重试工具
      • 数据修复入口
      • 隐私保护
    • 五十二、SQL 设计审查清单
    • 五十三、代码审查清单
    • 五十四、业务指标与服务等级目标
      • 用户体验指标
      • 数据正确性指标
      • 异步处理指标
      • 目标设定
    • 五十五、业务边界与法律合规提醒
    • 五十六、案例复盘模板
      • 背景
      • 约束
      • 问题
      • 影响
      • 根因
      • 处理
      • 验证
      • 教训
    • 五十七、完整场景演练:最后一件商品
      • 初始数据
      • 并发执行
      • 结果检查
      • 反例:先查后改
      • 反例:Redis 先减、数据库失败
    • 五十八、完整场景演练:重复提交与响应丢失
      • 初始条件
      • 客户端行为
      • 错误重试方式
      • 用户修改请求
    • 五十九、完整场景演练:支付成功与关闭任务竞争
      • 事件时间
      • 关闭任务执行
      • 支付回调执行
      • 设计必须回答的问题
    • 六十、编码规范与可维护性
      • 命名
      • 方法拆分
      • 注释
      • 配置
    • 六十一、学习顺序建议
      • 第一步:掌握 HTTP 与浏览器交互
      • 第二步:掌握服务端基础
      • 第三步:掌握关系型数据库
      • 第四步:练习业务状态建模
      • 第五步:学习可靠消息
      • 第六步:学习生产验证
      • 第七步:复盘真实故障
    • 六十二、读者自测题
    • 六十三、自测题参考答案
    • 六十四、博客发布前校对清单
    • 六十五、系列化拆分建议
      • 第一篇:需求与全链路架构
      • 第二篇:数据库模型与库存并发
      • 第三篇:幂等与请求重试
      • 第四篇:订单状态机与超时取消
      • 第五篇:支付回调与退款
      • 第六篇:Outbox 与消息可靠性
      • 第七篇:前端状态和用户体验
      • 第八篇:测试、监控与上线
    • 六十六、文末交流问题
    • 六十七、API 调用示例补充
      • 查询幂等结果
      • 取消订单
      • 支付状态查询
      • 管理端重放事件
    • 六十八、订单状态迁移伪代码
    • 六十九、重试和故障矩阵
    • 七十、上线前端到端验收脚本
      • 场景一:正常购买
      • 场景二:重复提交
      • 场景三:库存耗尽
      • 场景四:支付回调重复
      • 场景五:订单到期
      • 场景六:响应丢失恢复
    • 七十一、代码实现的验收标准
    • 七十二、最终结论
    • 七十三、落地核对:接口到数据库的一致性
      • 创建接口检查
      • 库存写入检查
      • 订单持久化检查
      • 支付处理检查
      • 异步事件检查
      • 发布运维检查
    • 七十四、结语
    • 学习专栏
    • 往期文章

摘要: 面试中常见的“如何实现下单”不是只写一个接口。本文以电商商品下单为例,串起前端交互、API 契约、Java 服务、MySQL 库存并发控制、幂等、支付回调和异常恢复,并说明不同规模下如何做方案取舍。

适合读者: Java 后端、前端及全栈开发者 关键词: 全栈面试、订单、库存、幂等、MySQL

一、面试题与业务背景

面试官提问

请设计一个商品下单流程。用户可能重复点击提交,热门商品可能被多人同时购买,服务还会遇到超时、重试和支付回调重复。你会如何保证页面体验、订单正确性和库存不超卖?

业务场景

用户在商品详情页选择规格和数量后提交订单。系统需要校验商品状态和价格、扣减库存、创建待支付订单,并在支付成功后更新订单状态。这里的重点不是某个框架,而是把并发、重试和跨系统失败纳入设计。

下面的代码与容量数字是用于解释方案的示例,不代表特定线上系统数据。先以单体 Java 服务和 MySQL 为基线;缓存、消息队列等组件按业务规模引入。

目标与边界

  • 目标:不超卖;同一业务请求重试不重复创建订单;订单与库存变更可追踪、可恢复。
  • 边界:本文不展开完整的促销计算、购物车、物流和支付渠道接入。
  • 重要约
赞(0)
未经允许不得转载:网硕互联帮助中心 » 全栈面试实战:从商品详情到可靠下单,如何设计库存扣减链路?
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!