第374集用户取消订单Java微服务后端架构实战
|字数总计:4.3k|阅读时长:19分钟|阅读量:
用户取消订单Java微服务后端架构实战
1. 架构概述
用户取消订单系统是电商平台和租赁平台的核心模块,需要支持订单取消校验、商品返库存、优惠券取消使用和订单状态更新等关键功能。本篇文章将深入讲解如何基于Java微服务架构实现一个高性能、高可用、数据一致性的用户取消订单系统。
1.1 系统架构图
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 用户端 → 用户网关 → 订单服务 → 目录服务/用户服务 ↓ 身份认证 ↓ 判断订单是否允许取消 ↓ 如果不允许,返回不允许取消提示 ↓ 如果允许: 商品返库存 优惠券取消标记请求 优惠券取消使用处理 订单取消 返回取消信息
|
1.2 核心组件
- 用户网关(User Gateway):负责用户请求的接入、身份认证、请求路由
- 订单服务(Order Service):负责订单管理、订单取消校验、订单取消处理、流程编排
- 目录服务(Catalog Service):负责商品库存管理、商品返库存
- 用户服务(User Service):负责优惠券管理、优惠券取消使用
- 数据库(MySQL):持久化订单信息、商品库存信息、优惠券信息
- 分布式锁(Redisson):保证订单取消和库存返还的并发安全
- 分布式事务(Seata):保证取消流程的原子性和一致性
2. 用户网关服务实现
2.1 用户网关服务核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
@RestController @RequestMapping("/api/user/gateway") @Slf4j public class UserGatewayController {
@Autowired private AuthService authService; @Autowired private OrderServiceClient orderServiceClient;
@PostMapping("/order/cancel") public Result<OrderCancelResult> cancelOrder( @RequestHeader("Authorization") String token, @RequestBody OrderCancelRequest request) { try { UserInfo userInfo = authService.authenticate(token); if (userInfo == null) { return Result.error("身份认证失败"); } request.setUserId(userInfo.getUserId()); OrderCancelResult result = orderServiceClient.cancelOrder(request); if (!result.isSuccess()) { return Result.error(result.getMessage()); } log.info("用户取消订单成功: userId={}, orderId={}, orderNo={}", userInfo.getUserId(), request.getOrderId(), result.getOrderNo()); return Result.success(result); } catch (Exception e) { log.error("用户取消订单失败: orderId={}, error={}", request.getOrderId(), e.getMessage(), e); return Result.error("取消订单失败: " + e.getMessage()); } } }
|
2.2 身份认证服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
@Service @Slf4j public class AuthService {
@Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private UserServiceClient userServiceClient;
public UserInfo authenticate(String token) { try { String userId = parseToken(token); if (StringUtils.isEmpty(userId)) { return null; } String userCacheKey = "user:info:" + userId; UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userCacheKey); if (userInfo != null) { return userInfo; } userInfo = userServiceClient.getUserInfo(userId); if (userInfo != null) { redisTemplate.opsForValue().set(userCacheKey, userInfo, 30, TimeUnit.MINUTES); } return userInfo; } catch (Exception e) { log.error("身份认证失败: token={}, error={}", token, e.getMessage(), e); return null; } }
private String parseToken(String token) { if (StringUtils.isEmpty(token) || !token.startsWith("Bearer ")) { return null; } String jwtToken = token.substring(7); return extractUserIdFromJWT(jwtToken); }
private String extractUserIdFromJWT(String jwtToken) { return "user123"; } }
|
3. 订单服务实现
3.1 订单服务核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
@Service @Slf4j public class OrderService {
@Autowired private OrderMapper orderMapper; @Autowired private CatalogServiceClient catalogServiceClient; @Autowired private UserServiceClient userServiceClient; @Autowired private RedissonClient redissonClient;
@GlobalTransactional(rollbackFor = Exception.class) public OrderCancelResult cancelOrder(OrderCancelRequest request) { String lockKey = "order:cancel:lock:" + request.getOrderId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(10, TimeUnit.SECONDS)) { Order order = orderMapper.selectById(request.getOrderId()); if (order == null) { return OrderCancelResult.failed("订单不存在"); } if (!order.getUserId().equals(request.getUserId())) { return OrderCancelResult.failed("无权限取消该订单"); } if (!isOrderAllowedToCancel(order)) { return OrderCancelResult.failed("订单状态不允许取消,当前状态: " + order.getStatus()); } StockReturnRequest stockRequest = new StockReturnRequest(); stockRequest.setProductId(order.getProductId()); stockRequest.setQuantity(order.getQuantity()); stockRequest.setOrderId(order.getId()); stockRequest.setOrderNo(order.getOrderNo()); StockReturnResult stockResult = catalogServiceClient.returnStock(stockRequest); if (!stockResult.isSuccess()) { return OrderCancelResult.failed("商品返库存失败: " + stockResult.getMessage()); } if (StringUtils.isNotEmpty(order.getCouponIds())) { List<Long> couponIds = Arrays.stream(order.getCouponIds().split(",")) .map(Long::parseLong) .collect(Collectors.toList()); CouponCancelRequest couponRequest = new CouponCancelRequest(); couponRequest.setUserId(request.getUserId()); couponRequest.setCouponIds(couponIds); couponRequest.setOrderId(order.getId()); couponRequest.setOrderNo(order.getOrderNo()); CouponCancelResult couponResult = userServiceClient.cancelCoupons(couponRequest); if (!couponResult.isSuccess()) { catalogServiceClient.rollbackStockReturn(stockRequest); return OrderCancelResult.failed("优惠券取消失败: " + couponResult.getMessage()); } } order.setStatus(OrderStatus.CANCELLED.getCode()); order.setCancelReason(request.getCancelReason()); order.setCancelTime(new Date()); order.setUpdateTime(new Date()); orderMapper.updateById(order); log.info("订单取消成功: orderId={}, orderNo={}, userId={}", order.getId(), order.getOrderNo(), request.getUserId()); OrderCancelResult result = new OrderCancelResult(); result.setSuccess(true); result.setOrderId(order.getId()); result.setOrderNo(order.getOrderNo()); result.setStatus(OrderStatus.CANCELLED.getCode()); result.setMessage("订单取消成功"); return result; } else { return OrderCancelResult.failed("取消订单操作超时,请稍后再试"); } } catch (Exception e) { log.error("取消订单失败: orderId={}, userId={}, error={}", request.getOrderId(), request.getUserId(), e.getMessage(), e); return OrderCancelResult.failed("取消订单失败: " + e.getMessage()); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }
private boolean isOrderAllowedToCancel(Order order) { String status = order.getStatus(); return OrderStatus.UNPAID.getCode().equals(status) || OrderStatus.PAID.getCode().equals(status); }
public OrderCancelCheckResult checkOrderCancelAllowed(Long orderId, Long userId) { try { Order order = orderMapper.selectById(orderId); if (order == null) { return OrderCancelCheckResult.failed("订单不存在"); } if (!order.getUserId().equals(userId)) { return OrderCancelCheckResult.failed("无权限取消该订单"); } boolean allowed = isOrderAllowedToCancel(order); OrderCancelCheckResult result = new OrderCancelCheckResult(); result.setAllowed(allowed); result.setOrderId(orderId); result.setOrderNo(order.getOrderNo()); result.setCurrentStatus(order.getStatus()); result.setMessage(allowed ? "订单可以取消" : "订单状态不允许取消"); return result; } catch (Exception e) { log.error("检查订单是否允许取消失败: orderId={}, error={}", orderId, e.getMessage(), e); return OrderCancelCheckResult.failed("检查失败: " + e.getMessage()); } } }
|
4. 目录服务实现
4.1 目录服务核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
@Service @Slf4j public class CatalogService {
@Autowired private ProductStockMapper productStockMapper; @Autowired private RedissonClient redissonClient;
@Transactional(rollbackFor = Exception.class) public StockReturnResult returnStock(StockReturnRequest request) { String lockKey = "stock:return:lock:" + request.getProductId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(10, TimeUnit.SECONDS)) { ProductStock stock = productStockMapper.selectByProductId(request.getProductId()); if (stock == null) { return StockReturnResult.failed("商品库存信息不存在"); } stock.setAvailableStock(stock.getAvailableStock() + request.getQuantity()); stock.setReservedStock(stock.getReservedStock() - request.getQuantity()); stock.setUpdateTime(new Date()); productStockMapper.updateById(stock); log.info("商品返库存成功: productId={}, quantity={}, availableStock={}, orderId={}", request.getProductId(), request.getQuantity(), stock.getAvailableStock(), request.getOrderId()); StockReturnResult result = new StockReturnResult(); result.setSuccess(true); result.setProductId(request.getProductId()); result.setReturnedQuantity(request.getQuantity()); result.setRemainingStock(stock.getAvailableStock()); result.setMessage("库存返还成功"); return result; } else { return StockReturnResult.failed("库存操作超时,请稍后再试"); } } catch (Exception e) { log.error("商品返库存失败: productId={}, quantity={}, orderId={}, error={}", request.getProductId(), request.getQuantity(), request.getOrderId(), e.getMessage(), e); return StockReturnResult.failed("库存返还失败: " + e.getMessage()); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }
@Transactional(rollbackFor = Exception.class) public void rollbackStockReturn(StockReturnRequest request) { String lockKey = "stock:return:lock:" + request.getProductId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(10, TimeUnit.SECONDS)) { ProductStock stock = productStockMapper.selectByProductId(request.getProductId()); if (stock != null) { stock.setAvailableStock(stock.getAvailableStock() - request.getQuantity()); stock.setReservedStock(stock.getReservedStock() + request.getQuantity()); stock.setUpdateTime(new Date()); productStockMapper.updateById(stock); log.info("库存返还回滚成功: productId={}, quantity={}", request.getProductId(), request.getQuantity()); } } } catch (Exception e) { log.error("库存返还回滚失败: productId={}, quantity={}, error={}", request.getProductId(), request.getQuantity(), e.getMessage(), e); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
|
5. 用户服务实现
5.1 用户服务核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
@Service @Slf4j public class UserService {
@Autowired private UserCouponMapper userCouponMapper; @Autowired private RedissonClient redissonClient;
@Transactional(rollbackFor = Exception.class) public CouponCancelResult cancelCoupons(CouponCancelRequest request) { String lockKey = "coupon:cancel:lock:" + request.getUserId(); RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(10, TimeUnit.SECONDS)) { List<Long> cancelledCouponIds = new ArrayList<>(); for (Long couponId : request.getCouponIds()) { UserCoupon userCoupon = userCouponMapper.selectByUserIdAndCouponId( request.getUserId(), couponId); if (userCoupon == null) { return CouponCancelResult.failed("优惠券不存在: " + couponId); } if (!CouponStatus.USED.getCode().equals(userCoupon.getStatus())) { log.warn("优惠券状态不是已使用,跳过: couponId={}, status={}", couponId, userCoupon.getStatus()); continue; } if (userCoupon.getOrderId() != null && !userCoupon.getOrderId().equals(request.getOrderId())) { log.warn("优惠券不是该订单使用的,跳过: couponId={}, orderId={}", couponId, request.getOrderId()); continue; } userCoupon.setStatus(CouponStatus.UNUSED.getCode()); userCoupon.setUseTime(null); userCoupon.setOrderId(null); userCoupon.setOrderNo(null); userCoupon.setOrderAmount(null); userCoupon.setUpdateTime(new Date()); userCouponMapper.updateById(userCoupon); cancelledCouponIds.add(couponId); } log.info("优惠券取消使用成功: userId={}, orderId={}, cancelledCouponIds={}", request.getUserId(), request.getOrderId(), cancelledCouponIds); CouponCancelResult result = new CouponCancelResult(); result.setSuccess(true); result.setCancelledCouponIds(cancelledCouponIds); result.setMessage("优惠券取消使用成功"); return result; } else { return CouponCancelResult.failed("优惠券操作超时,请稍后再试"); } } catch (Exception e) { log.error("优惠券取消使用失败: userId={}, orderId={}, couponIds={}, error={}", request.getUserId(), request.getOrderId(), request.getCouponIds(), e.getMessage(), e); return CouponCancelResult.failed("优惠券取消使用失败: " + e.getMessage()); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }
public CouponCancelProcessResult processCouponCancel(CouponCancelProcessRequest request) { try { CouponCancelResult cancelResult = cancelCoupons(request.getCouponCancelRequest()); CouponCancelProcessResult result = new CouponCancelProcessResult(); result.setSuccess(cancelResult.isSuccess()); result.setCancelledCouponIds(cancelResult.getCancelledCouponIds()); result.setMessage(cancelResult.getMessage()); return result; } catch (Exception e) { log.error("优惠券取消使用处理失败: error={}", e.getMessage(), e); return CouponCancelProcessResult.failed("处理失败: " + e.getMessage()); } } }
|
6. 数据模型定义
6.1 订单取消请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
@Data public class OrderCancelRequest {
private Long userId;
private Long orderId;
private String cancelReason; }
|
6.2 订单取消结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
@Data public class OrderCancelResult {
private Boolean success;
private Long orderId;
private String orderNo;
private String status;
private String message; public static OrderCancelResult failed(String message) { OrderCancelResult result = new OrderCancelResult(); result.setSuccess(false); result.setMessage(message); return result; } }
|
6.3 订单取消检查结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
@Data public class OrderCancelCheckResult {
private Boolean allowed;
private Long orderId;
private String orderNo;
private String currentStatus;
private String message; public static OrderCancelCheckResult failed(String message) { OrderCancelCheckResult result = new OrderCancelCheckResult(); result.setAllowed(false); result.setMessage(message); return result; } }
|
6.4 库存返还请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@Data public class StockReturnRequest {
private Long productId;
private Integer quantity;
private Long orderId;
private String orderNo; }
|
6.5 库存返还结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
@Data public class StockReturnResult {
private Boolean success;
private Long productId;
private Integer returnedQuantity;
private Integer remainingStock;
private String message; public static StockReturnResult failed(String message) { StockReturnResult result = new StockReturnResult(); result.setSuccess(false); result.setMessage(message); return result; } }
|
6.6 优惠券取消请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@Data public class CouponCancelRequest {
private Long userId;
private List<Long> couponIds;
private Long orderId;
private String orderNo; }
|
6.7 优惠券取消结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
@Data public class CouponCancelResult {
private Boolean success;
private List<Long> cancelledCouponIds;
private String message; public static CouponCancelResult failed(String message) { CouponCancelResult result = new CouponCancelResult(); result.setSuccess(false); result.setMessage(message); return result; } }
|
6.8 订单状态枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public enum OrderStatus { UNPAID("UNPAID", "未支付"), PAID("PAID", "已支付"), CANCELLED("CANCELLED", "已取消"), COMPLETED("COMPLETED", "已完成"), REFUNDED("REFUNDED", "已退款"); private final String code; private final String name; OrderStatus(String code, String name) { this.code = code; this.name = name; } public String getCode() { return code; } public String getName() { return name; } }
|
6.9 优惠券状态枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public enum CouponStatus { UNUSED("UNUSED", "未使用"), USED("USED", "已使用"), EXPIRED("EXPIRED", "已过期"); private final String code; private final String name; CouponStatus(String code, String name) { this.code = code; this.name = name; } public String getCode() { return code; } public String getName() { return name; } }
|
7. 数据库Mapper实现
7.1 OrderMapper
1 2 3 4 5 6 7 8 9 10 11 12
|
@Mapper public interface OrderMapper extends BaseMapper<Order> {
@Select("SELECT * FROM `order` WHERE order_no = #{orderNo} AND deleted = 0") Order selectByOrderNo(@Param("orderNo") String orderNo); }
|
7.2 UserCouponMapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Mapper public interface UserCouponMapper extends BaseMapper<UserCoupon> {
@Select("SELECT * FROM user_coupon " + "WHERE user_id = #{userId} AND coupon_id = #{couponId} AND deleted = 0") UserCoupon selectByUserIdAndCouponId(@Param("userId") Long userId, @Param("couponId") Long couponId); }
|
8. 数据库表设计
8.1 订单表(更新字段)
1 2 3 4
| ALTER TABLE `order` ADD COLUMN `cancel_reason` varchar(500) DEFAULT NULL COMMENT '取消原因' AFTER `status`, ADD COLUMN `cancel_time` datetime DEFAULT NULL COMMENT '取消时间' AFTER `cancel_reason`;
|
8.2 用户优惠券表(更新字段)
1 2 3 4 5 6
| ALTER TABLE `user_coupon` ADD COLUMN `order_id` bigint(20) DEFAULT NULL COMMENT '订单ID' AFTER `status`, ADD COLUMN `order_no` varchar(64) DEFAULT NULL COMMENT '订单号' AFTER `order_id`, ADD COLUMN `order_amount` decimal(15,2) DEFAULT NULL COMMENT '订单金额' AFTER `order_no`, ADD KEY `idx_order_id` (`order_id`);
|
9. 异常处理和回滚机制
9.1 订单取消异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
@Service @Slf4j public class OrderCancelExceptionHandler {
@Autowired private CatalogServiceClient catalogServiceClient; @Autowired private UserServiceClient userServiceClient;
public void handleCancelException(OrderCancelRequest request, Exception exception) { try { log.error("订单取消异常,开始回滚: orderId={}, error={}", request.getOrderId(), exception.getMessage()); Order order = orderMapper.selectById(request.getOrderId()); if (order == null) { return; } if (order.getProductId() != null && order.getQuantity() != null) { StockReturnRequest stockRequest = new StockReturnRequest(); stockRequest.setProductId(order.getProductId()); stockRequest.setQuantity(order.getQuantity()); stockRequest.setOrderId(order.getId()); try { catalogServiceClient.rollbackStockReturn(stockRequest); } catch (Exception e) { log.error("回滚库存返还失败: orderId={}, error={}", request.getOrderId(), e.getMessage(), e); } } if (StringUtils.isNotEmpty(order.getCouponIds())) { List<Long> couponIds = Arrays.stream(order.getCouponIds().split(",")) .map(Long::parseLong) .collect(Collectors.toList()); CouponCancelRequest couponRequest = new CouponCancelRequest(); couponRequest.setUserId(request.getUserId()); couponRequest.setCouponIds(couponIds); couponRequest.setOrderId(order.getId()); try { userServiceClient.rollbackCouponCancel(couponRequest); } catch (Exception e) { log.error("回滚优惠券取消失败: orderId={}, error={}", request.getOrderId(), e.getMessage(), e); } } } catch (Exception e) { log.error("订单取消异常处理失败: orderId={}, error={}", request.getOrderId(), e.getMessage(), e); } } }
|
10. 性能优化策略
10.1 订单状态缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
@Service @Slf4j public class OrderStatusCacheService {
@Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private OrderMapper orderMapper;
public String getOrderStatus(Long orderId) { String cacheKey = "order:status:" + orderId; String status = (String) redisTemplate.opsForValue().get(cacheKey); if (status != null) { return status; } Order order = orderMapper.selectById(orderId); if (order != null) { status = order.getStatus(); redisTemplate.opsForValue().set(cacheKey, status, 10, TimeUnit.MINUTES); } return status; }
public void updateOrderStatusCache(Long orderId, String status) { String cacheKey = "order:status:" + orderId; redisTemplate.opsForValue().set(cacheKey, status, 10, TimeUnit.MINUTES); }
public void deleteOrderStatusCache(Long orderId) { String cacheKey = "order:status:" + orderId; redisTemplate.delete(cacheKey); } }
|
11. 总结
本文详细介绍了用户取消订单的Java微服务架构实现,包括:
- 用户网关服务:负责用户请求接入、身份认证、请求路由
- 订单服务:负责订单管理、订单取消校验、订单取消处理、流程编排
- 目录服务:负责商品库存管理、商品返库存
- 用户服务:负责优惠券管理、优惠券取消使用
- 取消流程:
- 用户取消订单请求
- 身份认证
- 判断订单是否允许取消
- 如果不允许,返回不允许取消提示
- 如果允许:
- 商品返库存
- 优惠券取消标记请求
- 优惠券取消使用处理
- 订单取消
- 返回取消信息
- 分布式事务:使用Seata保证取消流程的原子性和一致性
- 异常处理:完整的异常处理和回滚机制
- 库存管理:支持库存返还和回滚
该架构具有以下优势:
- 数据一致性:分布式事务保证取消流程的原子性
- 高性能:分布式锁保证并发安全,支持高并发取消
- 高可用:数据库持久化,支持数据恢复
- 可扩展:微服务架构,支持水平扩展
- 完整性:完整的订单取消校验、库存返还、优惠券取消流程
- 可靠性:异常处理和回滚机制,保证数据一致性
通过本文的实战代码,可以快速搭建一个高性能、高可用、数据一致性的用户取消订单系统。