领域模型设计(核心类与关系)
订单基础属性封装
public class Order { private String id; // 唯一标识符(建议使用UUID或分布式ID生成算法) private Date createTime; // 创建时间戳 private User user; // 关联用户对象 private List<OrderItem> items; // 订单项集合(一对多关系) private BigDecimal totalAmount; // 总金额(避免浮点误差) private OrderStatus status; // 枚举型状态字段 // getters/setters + 构造方法 }
关键点:①使用
BigDecimal
处理金额计算;②通过组合模式管理子项;③状态机模式控制流程跳转。
public enum OrderStatus { PENDING_PAYMENT, PAID, SHIPPED, COMPLETED, CANCELLED }
订单项细化结构
public class OrderItem { private Product product; // 商品详情引用 private int quantity; // 购买数量 private BigDecimal unitPrice;// 单价快照(防止后续变价影响历史数据) // 可扩展字段:折扣策略ID、赠品标记等 }
设计考量:采用冗余存储确保数据一致性,即使原商品信息发生变化也不影响已下单记录。
数据库表结构规划(ORM映射示例)
表名 | 主要字段 | 索引建议 |
---|---|---|
t_order | id(PK), user_id(FK), total_amt, create_tm, status | (user_id), status |
t_order_item | order_id(FK), product_id(FK), qty, unit_price | (order_id, product_id) |
t_payment | order_id(UK), pay_type, transaction_no, amount, pay_time | order_id |
优化技巧:对高频查询字段建立复合索引,如按用户ID+状态筛选进行中订单时效率提升显著。
关键业务流程实现
✅ 创建订单流程
// Service层伪代码示例 public Order submitNewOrder(Long userId, List<CartItem> selectedItems) { // 1. 校验库存可用性(调用InventoryService预留接口) // 2. 计算实际应付总额(含优惠券抵扣逻辑) // 3. 生成待支付订单草案 Order draft = new Order(); draft.setUser(userRepository.findById(userId)); draft.setItems(convertCartToOrderItems(selectedItems)); draft.setStatus(OrderStatus.PENDING_PAYMENT); // 4. 开启事务批量插入明细&主表 orderRepository.save(draft); return draft; }
异常处理机制:当并发冲突导致超卖时,应抛出自定义异常并回滚事务,推荐使用Redis预减库存实现乐观锁。
⏳ 状态流转控制
通过状态模式限制合法转换路径:
PENDING → PAID → SHIPPED → COMPLETED ↓ CANCELLED
可在DAO层添加校验逻辑:
if (currentStatus == OrderStatus.PAID && targetStatus != OrderStatus.SHIPPED) { throw new IllegalStateException("无效的状态变更"); }
高级特性扩展建议
📦 分布式锁应用场景
对于秒杀场景下的订单创建,可采用Redisson实现分布式锁:
RLock lock = redissonClient.getLock("order_create_lock:" + goodsId); lock.lock(); try { // 双重检查剩余库存量 Integer remainStock = inventoryService.getAvailableStock(goodsId); if (requestQty > remainStock) throw new BusinessException("库存不足"); // 执行扣减操作... } finally { lock.unlock(); }
🔄 幂等性保障方案
支付回调接口需支持重复通知的处理:
String idempotentKey = "pay_callback:" + orderNo; if (redisTemplate.opsForValue().get(idempotentKey) != null) { return ResponseEntity.ok("已处理过该请求"); } else { redisTemplate.opsForValue().set(idempotentKey, "processed", 24, TimeUnit.HOURS); // 正常处理逻辑... }
典型代码片段参考
以下是Spring Boot环境下常用的分层架构示例:
Controller层
@PostMapping("/api/orders") public ResponseEntity<OrderVO> createOrder(@RequestBody CreateOrderDTO dto) { Order result = orderService.createOrder(dto); return ResponseEntity.status(HttpStatus.CREATED).body(convertToVO(result)); }
Service层核心方法
@Transactional(rollbackFor = Exception.class) public Order createOrder(CreateOrderDTO dto) { // 参数校验省略... User currentUser = securityContextHolder.getUser(); List<OrderItem> mappedItems = dto.getItems().stream() .map(item -> mapToEntity(item, currentUser)) .collect(Collectors.toList()); Order order = new Order(); order.setUser(currentUser); order.setItems(mappedItems); calculateTotalAmount(order); // 重新汇总防止前端篡改 return orderRepository.save(order); }
Mapper层(MyBatis)
<insert id="insertWithItems"> INSERT INTO t_order(user_id, total_amt, create_tm) VALUES(#{userId}, #{totalAmt}, NOW()) RETURNING id INTO #lastInsertId; INSERT INTO t_order_item(order_id, product_id, qty, unit_price) SELECT #{lastInsertId}, product_id, qty, unit_price FROM @itemsTable WHERE order_id=#{lastInsertId} </insert>
常见问题应对策略
场景 | 解决方案 |
---|---|
高并发下单超卖 | 预先冻结库存 + Redis原子操作递减 |
分布式事务一致性 | Seata框架或本地消息队列最终一致性 |
跨库关联查询慢 | ES建立宽表索引/CQRS模式分离读写 |
大促期间DB压力大 | ShardingSphere分库分表+读写分离架构 |
FAQs
Q1: 如何处理多线程下的订单编号生成冲突?
A: 推荐两种方案:①采用雪花算法(Snowflake)生成全局唯一ID;②数据库自增序列配合版本号乐观锁重试机制,前者更适合分布式环境,后者实现简单但存在理论碰撞概率。
Q2: 当第三方支付回调失败时如何补救?
A: 建立可靠重试机制:①首次失败立即人工干预;②后续每隔30分钟重试一次共持续24小时;③超过时限后标记为异常订单转人工审核通道,同时记录完整
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/89109.html