当前位置:网站首页 >  教程

电商预售系统实战:从零搭建高并发订单处理架构

时间:2026年05月23日 07:08:08 来源:易频IT社区

系统架构设计

电商预售系统的核心在于处理订单的异步创建和库存的预扣减。我们采用微服务架构,将系统拆分为以下核心模块:

服务划分

  • 商品服务:管理预售商品信息、库存
  • 订单服务:处理订单创建、状态流转
  • 支付服务:对接第三方支付渠道
  • 库存服务:负责库存的预扣减和释放
  • 定时任务服务:处理超时未支付订单

技术选型

Spring Boot 2.7.15 + MySQL 8.0 + Redis 7.0 + RabbitMQ 3.12

数据库设计

商品表设计

```sql CREATE TABLE `pre_sale_product` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `product_id` bigint(20) NOT NULL COMMENT '商品ID', `pre_sale_price` decimal(10,2) NOT NULL COMMENT '预售价格', `total_stock` int(11) NOT NULL COMMENT '预售总库存', `locked_stock` int(11) DEFAULT '0' COMMENT '已锁定库存', `start_time` datetime NOT NULL COMMENT '预售开始时间', `end_time` datetime NOT NULL COMMENT '预售结束时间', `delivery_time` datetime NOT NULL COMMENT '预计发货时间', `deposit_amount` decimal(10,2) NOT NULL COMMENT '定金金额', `final_payment_start` datetime NOT NULL COMMENT '尾款支付开始时间', `final_payment_end` datetime NOT NULL COMMENT '尾款支付结束时间', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:1-未开始 2-进行中 3-已结束', PRIMARY KEY (`id`), KEY `idx_product_time` (`product_id`,`start_time`,`end_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

预售订单表

```sql CREATE TABLE `pre_sale_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '订单号', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `product_id` bigint(20) NOT NULL COMMENT '商品ID', `deposit_amount` decimal(10,2) NOT NULL COMMENT '定金金额', `final_amount` decimal(10,2) DEFAULT NULL COMMENT '尾款金额', `total_amount` decimal(10,2) NOT NULL COMMENT '总金额', `deposit_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '定金状态:1-待支付 2-已支付 3-已退款', `final_status` tinyint(4) DEFAULT '0' COMMENT '尾款状态:0-未开始 1-待支付 2-已支付 3-已退款', `order_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '订单状态:1-定金待支付 2-定金已支付 3-尾款待支付 4-尾款已支付 5-已取消 6-已完成', `lock_expire_time` datetime DEFAULT NULL COMMENT '库存锁定过期时间', `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_user_status` (`user_id`,`order_status`), KEY `idx_lock_expire` (`lock_expire_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

核心功能实现

库存预扣减服务

电商预售系统实战:从零搭建高并发订单处理架构

库存扣减是预售系统的关键,必须保证在高并发下的数据一致性。

```java @Service public class StockService { @Autowired private RedisTemplate redisTemplate; @Autowired private PreSaleProductMapper productMapper; / 预扣减库存 @param productId 商品ID @param quantity 购买数量 @param expireMinutes 锁定过期时间(分钟) @return 锁定ID,用于后续确认或释放 / public String preDeductStock(Long productId, Integer quantity, Integer expireMinutes) { String lockKey = "stock:lock:" + productId; String stockKey = "stock:pre_sale:" + productId; // 使用Redis分布式锁 String lockId = UUID.randomUUID().toString(); Boolean lockAcquired = redisTemplate.opsForValue() .setIfAbsent(lockKey, lockId, 10, TimeUnit.SECONDS); if (Boolean.FALSE.equals(lockAcquired)) { throw new RuntimeException("系统繁忙,请稍后重试"); } try { // 检查并扣减Redis中的库存 Long currentStock = redisTemplate.opsForValue() .decrement(stockKey, quantity); if (currentStock != null && currentStock < 0) { // 库存不足,恢复库存 redisTemplate.opsForValue().increment(stockKey, quantity); throw new RuntimeException("库存不足"); } // 记录库存锁定 String lockRecordId = UUID.randomUUID().toString(); String lockRecordKey = "stock:lock_record:" + lockRecordId; Map lockRecord = new HashMap<>(); lockRecord.put("productId", productId.toString()); lockRecord.put("quantity", quantity.toString()); lockRecord.put("expireTime", LocalDateTime.now().plusMinutes(expireMinutes).toString()); redisTemplate.opsForHash().putAll(lockRecordKey, lockRecord); redisTemplate.expire(lockRecordKey, expireMinutes + 5, TimeUnit.MINUTES); return lockRecordId; } finally { // 释放分布式锁 String currentLockId = redisTemplate.opsForValue().get(lockKey); if (lockId.equals(currentLockId)) { redisTemplate.delete(lockKey); } } } } ```

订单创建服务

```java @Service @Transactional(rollbackFor = Exception.class) public class OrderService { @Autowired private StockService stockService; @Autowired private RabbitTemplate rabbitTemplate; / 创建预售订单 / public String createPreSaleOrder(CreateOrderDTO dto) { // 1. 验证预售活动 PreSaleProduct product = validatePreSale(dto.getProductId()); // 2. 预扣减库存 String lockRecordId = stockService.preDeductStock( dto.getProductId(), dto.getQuantity(), 30 // 锁定30分钟 ); // 3. 生成订单号 String orderNo = generateOrderNo(); // 4. 创建订单记录 PreSaleOrder order = new PreSaleOrder(); order.setOrderNo(orderNo); order.setUserId(dto.getUserId()); order.setProductId(dto.getProductId()); order.setDepositAmount(product.getDepositAmount()); order.setTotalAmount(product.getPreSalePrice().multiply( new BigDecimal(dto.getQuantity()))); order.setLockExpireTime(LocalDateTime.now().plusMinutes(30)); order.setOrderStatus(1); // 定金待支付 preSaleOrderMapper.insert(order); // 5. 发送延迟消息,30分钟后检查支付状态 OrderCheckMessage message = new OrderCheckMessage(); message.setOrderNo(orderNo); message.setCheckType("DEPOSIT_PAYMENT"); rabbitTemplate.convertAndSend( "order.delay.exchange", "order.check.routingKey", message, msg -> { msg.getMessageProperties().setDelay(30 60 1000); // 30分钟 return msg; } ); return orderNo; } } ```

支付流程实现

定金支付回调处理

```java @RestController @RequestMapping("/api/payment") public class PaymentController { @PostMapping("/deposit/callback") public String handleDepositCallback(@RequestBody PaymentCallbackDTO callback) { // 验证签名 if (!verifySignature(callback)) { return "FAIL"; } // 查询订单 PreSaleOrder order = orderService.getByOrderNo(callback.getOrderNo()); if (order == null || !order.getOrderStatus().equals(1)) { return "FAIL"; } // 更新订单状态 order.setDepositStatus(2); // 已支付 order.setOrderStatus(2); // 定金已支付 order.setLockExpireTime(null); // 清除锁定过期时间 orderService.updateOrder(order); // 发送尾款支付提醒 sendFinalPaymentRemind(order); return "SUCCESS"; } } ```

定时任务设计

超时订单处理

```java @Component public class OrderTimeoutTask { @Scheduled(fixedDelay = 60000) // 每分钟执行一次 public void handleTimeoutOrders() { // 查询超过30分钟未支付定金的订单 List timeoutOrders = orderMapper.selectTimeoutOrders( LocalDateTime.now().minusMinutes(30)); for (PreSaleOrder order : timeoutOrders) { try { // 释放库存 stockService.releaseStock(order.getProductId(), 1); // 更新订单状态为已取消 order.setOrderStatus(5); orderMapper.updateById(order); // 发送订单取消通知 notifyService.sendOrderCanceled(order.getUserId(), order.getOrderNo()); } catch (Exception e) { log.error("处理超时订单失败: {}", order.getOrderNo(), e); } } } } ```

配置部署

Redis配置

在application.yml中添加Redis配置:

```yaml spring: redis: host: 127.0.0.1 port: 6379 password: your_password_here database: 0 lettuce: pool: max-active: 8 max-wait: -1ms max-idle: 8 min-idle: 0 timeout: 5000ms ```

RabbitMQ配置

```yaml spring: rabbitmq: host: 127.0.0.1 port: 5672 username: admin password: admin123 virtual-host: / 开启延迟消息插件支持 dynamic: true 确认模式 publisher-confirm-type: correlated publisher-returns: true listener: simple: acknowledge-mode: manual ```

延迟队列配置

```java @Configuration public class RabbitMQConfig { @Bean public CustomExchange orderDelayExchange() { Map args = new HashMap<>(); args.put("x-delayed-type", "direct"); return new CustomExchange( "order.delay.exchange", "x-delayed-message", true, false, args ); } @Bean public Queue orderCheckQueue() { return new Queue("order.check.queue", true); } @Bean public Binding orderCheckBinding() { return BindingBuilder .bind(orderCheckQueue()) .to(orderDelayExchange()) .with("order.check.routingKey") .noargs(); } } ```

压力测试与优化

JMeter测试脚本

创建create_order.jmx文件,模拟高并发下单场景:

```xml false true false BASE_URL http://localhost:8080 = continue false 100 100 10 false false {"userId":${__Random(1,10000)},"productId":1001,"quantity":1} = localhost 8080 http /api/order/create POST true false true false ```

性能优化建议

  • 数据库层面:为order_status、created_time字段建立联合索引
  • 缓存层面:使用Redis集群,设置合理的过期时间
  • 代码层面:异步处理非核心逻辑,如发送通知、记录日志
  • 监控层面:集成Prometheus监控关键指标,设置报警阈值

错误处理与日志

全局异常处理

```java @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result handleBusinessException(BusinessException e) { log.error("业务异常: {}", e.getMessage(), e); return Result.error(e.getCode(), e.getMessage()); } @ExceptionHandler(Exception.class) public Result handleException(Exception e) { log.error("系统异常: {}", e.getMessage(), e); return Result.error(500, "系统繁忙,请稍后重试"); } } ```

关键日志记录

```java @Component public class OrderLogAspect { @Around("@annotation(com.example.annotation.OperateLog)") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); try { Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); log.info("操作成功 | 方法: {} | 耗时: {}ms | 参数: {}", joinPoint.getSignature().getName(), endTime - startTime, Arrays.toString(joinPoint.getArgs())); return result; } catch (Exception e) {
标签 电商预售

相关推荐

最新

热门

推荐

精选

标签

易频IT社区是综合性互联网IT技术门户网站,专注分享网络技术、服务器运维、网络安全、编程开发、系统架构、云计算、大数据等行业干货,实时更新IT行业资讯、零基础教程、实战案例,为IT从业者、技术爱好者提供专业的学习交流平台。

Copyright © 2021-2026 易频IT社区. All Rights Reserved. 备案号:闽ICP备2023013482号 网站地图