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); //這種寫法是調用代理對象方法,方法是有事務處理的
}