UserCouponServiceImpl
/*** 兑换码兑换优惠券* @param code*/@Transactional@Overridepublic void exchangeCoupon(String code) {//1、校验code是否为空if (StringUtils.isBlank(code)) {throw new BadRequestException("非法参数!");}//2、解析兑换码,得到自增idlong serialNum = CodeUtil.parseCode(code); //获取自增id//3、判断兑换码是否已兑换,采用redis的bitMap命令 setbit key offset value=1 如果方法返回true,则说明该兑换码已兑换boolean result = exchangeCodeService.updateExchangeCodeMark(serialNum, true);if (result) {//说明兑换码已经被兑换throw new BizIllegalException("该兑换码已被兑换!");}try {//4、判断兑换码是否存在,根据自增id 查询兑换码信息ExchangeCode exchangeCode = exchangeCodeService.getById(serialNum);if (exchangeCode == null) {throw new BizIllegalException("该兑换码不存在!");}//5、判断是否过期if (LocalDateTime.now().isAfter(exchangeCode.getExpiredTime())) {throw new BizIllegalException("该兑换码已过期!");}//校验并生成用户券Long userId = UserContext.getUser();//查询优惠券信息Coupon coupon = couponMapper.selectById(exchangeCode.getExchangeTargetId());if (coupon == null) {throw new BizIllegalException("该优惠券不存在!");}//6、判断是否超出限领的数量//7、优惠券已发放数量+1//8、生成用户券//9、更新兑换码的状态synchronized (userId.toString().intern()) {//从AOP上下文中,获取当前类代理对象IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();//checkAndCreateUserCoupon(userId, coupon, serialNum);//这种写法是调用原对象的方法userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon, serialNum); //这种写法是调用代理对象方法,方法是有事务处理的}} catch (Exception e) {//10、将兑换码的状态重置exchangeCodeService.updateExchangeCodeMark(serialNum, false);throw e;}}
只需要在调用checkAndCreateUserCoupon时加上悲观锁处理方式,以及处理事务失效即可,更改代码如下:
synchronized (userId.toString().intern()) {
//从AOP上下文中,获取当前类代理对象
IUserCouponService userCouponServiceProxy = (IUserCouponService) AopContext.currentProxy();
//checkAndCreateUserCoupon(userId, coupon, serialNum);//这种写法是调用原对象的方法
userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon, serialNum); //这种写法是调用代理对象方法,方法是有事务处理的
}