当前位置: 首页 > news >正文

学习日报 20250930|优惠券事务处理模块

以下是整合后的优惠券事务处理模块,包含异常处理、事务管理及核心业务逻辑,各组件职责明确且注释清晰:

模块结构

coupon-transaction/
├── exception/                // 自定义异常类
│   └── CheckUserCouponException.java
├── service/                  // 服务接口与实现
│   ├── ICouponTransactionService.java
│   └── CouponTransactionServiceImpl.java
└── entity/                   // 核心实体类├── Order.java            // 订单实体└── UserCoupon.java       // 用户优惠券实体

1. 自定义异常类(异常处理)

package com.coupon.transaction.exception;/*** 优惠券校验异常:用于优惠券校验失败时抛出,触发事务回滚*/
public class CheckUserCouponException extends RuntimeException {// 异常编码(可用于前端展示具体错误类型)private String errorCode;public CheckUserCouponException(String message) {super(message);}public CheckUserCouponException(String message, String errorCode) {super(message);this.errorCode = errorCode;}public String getErrorCode() {return errorCode;}
}

2. 核心实体类

订单实体(Order.java)
package com.coupon.transaction.entity;import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 订单实体:与优惠券核销关联的订单信息*/
@Data
public class Order {private Long id;                 // 订单IDprivate Long userId;             // 用户IDprivate BigDecimal totalAmount;  // 订单总金额private BigDecimal payAmount;    // 实付金额(扣减优惠券后)private Integer status;          // 订单状态:0-待支付 1-已完成 2-已取消private LocalDateTime createTime;// 创建时间private LocalDateTime payTime;   // 支付时间
}
用户优惠券实体(UserCoupon.java)
package com.coupon.transaction.entity;import lombok.Data;
import java.time.LocalDateTime;/*** 用户优惠券实体:记录用户持有的优惠券状态及使用信息*/
@Data
public class UserCoupon {private Long id;                 // 优惠券IDprivate Long userId;             // 用户IDprivate Long couponTemplateId;   // 优惠券模板IDprivate Integer status;          // 状态:0-未使用 1-已核销 2-已过期private LocalDateTime expireTime;// 过期时间private Long orderId;            // 关联订单ID(核销后填充)private LocalDateTime useTime;   // 核销时间
}

3. 事务服务接口

package com.coupon.transaction.service;import com.coupon.transaction.entity.Order;
import com.coupon.transaction.entity.UserCoupon;
import com.coupon.transaction.exception.CheckUserCouponException;
import java.util.List;/*** 优惠券事务服务接口:定义订单与优惠券关联的核心事务操作*/
public interface ICouponTransactionService {/*** 订单完成后核销优惠券* 包含订单状态更新、优惠券核销、金额计算等操作,保证事务一致性* @param order 已支付的订单* @param userCoupons 用户选择的待核销优惠券列表* @throws CheckUserCouponException 优惠券校验失败时抛出*/void writeOffCouponsAfterOrderPay(Order order, List<UserCoupon> userCoupons) throws CheckUserCouponException;
}

4. 事务服务实现类(核心逻辑)

package com.coupon.transaction.service;import com.coupon.transaction.entity.Order;
import com.coupon.transaction.entity.UserCoupon;
import com.coupon.transaction.exception.CheckUserCouponException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;/*** 优惠券事务服务实现:基于Spring事务管理,保证订单与优惠券操作的原子性*/
@Slf4j
@Service
public class CouponTransactionServiceImpl implements ICouponTransactionService {/*** 订单支付后核销优惠券:事务管理核心方法* 注解说明:* - @Transactional:声明事务,默认 RuntimeException 触发回滚* - rollbackFor = Exception.class:指定所有异常都回滚(根据业务调整)*/@Override@Transactional(rollbackFor = Exception.class)public void writeOffCouponsAfterOrderPay(Order order, List<UserCoupon> userCoupons) {log.info("开始处理订单[{}]的优惠券核销", order.getId());// 1. 校验订单状态(必须为已支付状态)if (order.getStatus() != 1) {throw new CheckUserCouponException("订单未支付,无法核销优惠券", "ORDER_STATUS_INVALID");}// 2. 校验优惠券合法性(批量校验)validateUserCoupons(order, userCoupons);// 3. 计算优惠券总抵扣金额(根据优惠券类型计算,此处简化)BigDecimal totalDiscount = calculateTotalDiscount(userCoupons);// 4. 更新订单实付金额(总金额 - 抵扣金额)order.setPayAmount(order.getTotalAmount().subtract(totalDiscount));updateOrder(order); // 实际项目中调用DAO层更新数据库// 5. 批量核销优惠券(更新状态、关联订单、记录时间)writeOffBatch(userCoupons, order.getId());log.info("订单[{}]优惠券核销完成,总抵扣金额:{}", order.getId(), totalDiscount);}/*** 校验用户选择的优惠券是否合法* 包含用户匹配、状态、有效期、订单关联等校验*/private void validateUserCoupons(Order order, List<UserCoupon> coupons) {if (coupons == null || coupons.isEmpty()) {return; // 无优惠券时无需校验}for (UserCoupon coupon : coupons) {// 校验1:优惠券归属当前用户if (!coupon.getUserId().equals(order.getUserId())) {throw new CheckUserCouponException("优惠券[" + coupon.getId() + "]不属于当前用户", "COUPON_USER_MISMATCH");}// 校验2:优惠券状态为未使用if (coupon.getStatus() != 0) {throw new CheckUserCouponException("优惠券[" + coupon.getId() + "]状态异常(当前状态:" + coupon.getStatus() + ")", "COUPON_STATUS_INVALID");}// 校验3:优惠券未过期if (coupon.getExpireTime().isBefore(LocalDateTime.now())) {throw new CheckUserCouponException("优惠券[" + coupon.getId() + "]已过期", "COUPON_EXPIRED");}}}/*** 计算优惠券总抵扣金额(简化逻辑,实际需根据优惠券类型(折扣/现金)计算)*/private BigDecimal calculateTotalDiscount(List<UserCoupon> coupons) {BigDecimal total = BigDecimal.ZERO;for (UserCoupon coupon : coupons) {// 假设为现金券,抵扣金额固定(实际需从模板获取规则)total = total.add(new BigDecimal(10)); // 示例:每张券抵扣10元}return total;}/*** 批量更新优惠券状态为"已核销"*/private void writeOffBatch(List<UserCoupon> coupons, Long orderId) {LocalDateTime now = LocalDateTime.now();for (UserCoupon coupon : coupons) {coupon.setStatus(1);          // 状态改为已核销coupon.setOrderId(orderId);   // 关联订单IDcoupon.setUseTime(now);       // 记录核销时间updateUserCoupon(coupon);     // 实际项目中调用DAO层更新数据库}}// ------------------------------ 以下为模拟DAO层操作(实际项目中替换为MyBatis/MyBatis-Plus) ------------------------------private void updateOrder(Order order) {log.info("数据库操作:更新订单[{}]实付金额为{}", order.getId(), order.getPayAmount());}private void updateUserCoupon(UserCoupon coupon) {log.info("数据库操作:核销优惠券[{}],状态更新为{}", coupon.getId(), coupon.getStatus());}
}

模块说明

  1. 核心功能:实现订单支付后优惠券核销的完整事务流程,确保订单状态更新与优惠券核销操作的原子性(要么全部成功,要么全部回滚)。

  2. 事务保证

    • 通过 @Transactional 注解声明事务,当抛出 CheckUserCouponException 或其他异常时,自动回滚数据库操作。
    • 包含订单状态校验、优惠券合法性校验(用户匹配、状态、有效期)等前置校验,避免无效操作。
  3. 异常处理

    • 自定义 CheckUserCouponException 用于标识优惠券校验失败场景,包含错误码便于前端展示具体原因。
    • 异常抛出后触发事务回滚,保证数据一致性。
  4. 扩展性

    • 金额计算逻辑可根据优惠券类型(折扣券、现金券等)扩展。
    • 校验规则可通过配置化(如从优惠券模板读取规则)进一步灵活化。

该模块可直接集成到电商系统的订单支付流程中,解决优惠券核销与订单状态同步的一致性问题。

http://www.dtcms.com/a/427031.html

相关文章:

  • 【Nest.js】模块之间依赖关系,以及导出导入链的完整性
  • MyBatis —— 多表操作和注解开发
  • 自动化脚本的自动化执行实践
  • 有颜二维码 1.0.5| 告别单调,一键生成有颜色的二维码
  • 信创浪潮下的国产组态软件——紫金桥RealSCADA
  • 做网站新闻移动动态网络规划设计师资料及视频教程
  • 机器学习之三大学习范式:监督学习、无监督学习、强化学习
  • 18002.机器人电机姿态控制
  • mysql语句基本操作之select查询
  • 做mp3链接的网站宁波专业seo外包
  • Spring Boot 集成 EHCache 缓存解决方案
  • Spring Boot 缓存与验证码生成
  • 进攻------绕后------互换野区
  • Unity 3D笔记(脚本部分)——《B站阿发你好》
  • C++之类的组合
  • 服装购物网站策划书wordpress菜单栏移动下移
  • 【第五章:计算机视觉-项目实战之生成对抗网络实战】1.对抗生成网络原理-(1)对抗生成网络算法基础知识:基本思想、GAN的基本架构、应用场景、标注格式
  • win10软实时设置
  • leetcode 812. 最大三角形面积 简单
  • 机器学习+数字孪生:从诊断到自主决策的跨越
  • 若依前后端分离版学习笔记(十八)——页面权限,页签缓存以及图标,字典,参数的使用
  • 莱芜网站建设哪家好在线logo制作生成免费
  • 哈尔滨网站建设价格网站设计怎么学
  • 再发《管理世界》!智能制造试点DID(2000-2023)
  • SpringCloudGateway:像快递分拣中心一样的API网关
  • 真家宽IP vs 数据中心IP:Cliproxy为何成为跨境电商首选?
  • 声光可调滤光器(AOTF):光谱相机的“电子调谐旋钮”
  • skynet-socket.lua源码分析
  • 悠然无界大模型BLM-1.0:跨空间、跨任务与跨本体泛化的里程碑
  • 安康那个公司做网站好wordpress主题滑动