Authored by LUOXC

Merge branch 'hotfix-20191028' into test6.9.14

# Conflicts:
#	promotion/src/main/java/com/yohoufo/promotion/service/impl/CouponServiceImpl.java
@@ -2,6 +2,7 @@ package com.yohoufo.promotion.service.impl; @@ -2,6 +2,7 @@ package com.yohoufo.promotion.service.impl;
2 2
3 import com.google.common.collect.Lists; 3 import com.google.common.collect.Lists;
4 import com.google.common.collect.Range; 4 import com.google.common.collect.Range;
  5 +import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
5 import com.yoho.error.ServiceError; 6 import com.yoho.error.ServiceError;
6 import com.yoho.error.exception.ServiceException; 7 import com.yoho.error.exception.ServiceException;
7 import com.yohobuy.ufo.model.promotion.UserCouponsBo; 8 import com.yohobuy.ufo.model.promotion.UserCouponsBo;
@@ -14,6 +15,9 @@ import com.yohobuy.ufo.model.promotion.request.UserCouponListReq; @@ -14,6 +15,9 @@ import com.yohobuy.ufo.model.promotion.request.UserCouponListReq;
14 import com.yohobuy.ufo.model.promotion.response.CouponInfo; 15 import com.yohobuy.ufo.model.promotion.response.CouponInfo;
15 import com.yohobuy.ufo.model.promotion.response.CouponInfoListBo; 16 import com.yohobuy.ufo.model.promotion.response.CouponInfoListBo;
16 import com.yohobuy.ufo.model.promotion.response.CouponSendBo; 17 import com.yohobuy.ufo.model.promotion.response.CouponSendBo;
  18 +import com.yohoufo.common.exception.UfoServiceException;
  19 +import com.yohoufo.common.lock.RedisLock;
  20 +import com.yohoufo.common.lock.RedisLockFactory;
17 import com.yohoufo.common.utils.DateUtil; 21 import com.yohoufo.common.utils.DateUtil;
18 import com.yohoufo.dal.promotion.CouponMapper; 22 import com.yohoufo.dal.promotion.CouponMapper;
19 import com.yohoufo.dal.promotion.UserCouponMapper; 23 import com.yohoufo.dal.promotion.UserCouponMapper;
@@ -32,6 +36,7 @@ import java.time.LocalDateTime; @@ -32,6 +36,7 @@ import java.time.LocalDateTime;
32 import java.time.LocalTime; 36 import java.time.LocalTime;
33 import java.time.ZoneOffset; 37 import java.time.ZoneOffset;
34 import java.util.*; 38 import java.util.*;
  39 +import java.util.concurrent.TimeUnit;
35 import java.util.function.Function; 40 import java.util.function.Function;
36 import java.util.stream.Collectors; 41 import java.util.stream.Collectors;
37 42
@@ -53,6 +58,9 @@ public class CouponServiceImpl implements ICouponService { @@ -53,6 +58,9 @@ public class CouponServiceImpl implements ICouponService {
53 @Autowired 58 @Autowired
54 SingleCentCouponService singleCentSyncCoupNumService; 59 SingleCentCouponService singleCentSyncCoupNumService;
55 60
  61 + @Autowired
  62 + private RedisLockFactory redisLockFactory;
  63 +
56 64
57 private final Logger logger = LoggerFactory.getLogger(getClass()); 65 private final Logger logger = LoggerFactory.getLogger(getClass());
58 66
@@ -202,6 +210,7 @@ public class CouponServiceImpl implements ICouponService { @@ -202,6 +210,7 @@ public class CouponServiceImpl implements ICouponService {
202 logger.warn("sendCoupon query coupon info,coupontype is null:{}", couponToken); 210 logger.warn("sendCoupon query coupon info,coupontype is null:{}", couponToken);
203 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_NOT_EXISTS); 211 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_NOT_EXISTS);
204 } 212 }
  213 +
205 Coupon coupon = couponAndType.getCoupon(); 214 Coupon coupon = couponAndType.getCoupon();
206 //check receive start time 215 //check receive start time
207 if(receiveStartTimeChkNecessary){ 216 if(receiveStartTimeChkNecessary){
@@ -211,7 +220,7 @@ public class CouponServiceImpl implements ICouponService { @@ -211,7 +220,7 @@ public class CouponServiceImpl implements ICouponService {
211 220
212 if(!repeatable){ 221 if(!repeatable){
213 // 校验是否可以领取(重复领取,时间是否合法,状态) 222 // 校验是否可以领取(重复领取,时间是否合法,状态)
214 - checkCanAcquire(uid, couponToken, couponAndType); 223 + redisLock = checkCanAcquire(uid, couponToken, couponAndType);
215 } 224 }
216 225
217 if (coupon.getStatus() != CouponsStatusEnum.VALID.getCode()){ 226 if (coupon.getStatus() != CouponsStatusEnum.VALID.getCode()){
@@ -235,19 +244,16 @@ public class CouponServiceImpl implements ICouponService { @@ -235,19 +244,16 @@ public class CouponServiceImpl implements ICouponService {
235 } 244 }
236 245
237 int count = 0; 246 int count = 0;
238 - // 不可重复  
239 - if (!repeatable){  
240 - count = userCouponMapper.insertWhere(userCoupon);  
241 - }else{  
242 count = userCouponMapper.insert(userCoupon); 247 count = userCouponMapper.insert(userCoupon);
243 - }  
244 -  
245 if (count == 0){ 248 if (count == 0){
246 logger.info("can not repeatable acquire coupon. uid is {}, coupon is {}", uid, couponToken); 249 logger.info("can not repeatable acquire coupon. uid is {}, coupon is {}", uid, couponToken);
247 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_RECEIVED); 250 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_RECEIVED);
248 } 251 }
249 252
250 logger.info("senCoupon success,{},{},{},{}", uid, couponToken, couponCode, count); 253 logger.info("senCoupon success,{},{},{},{}", uid, couponToken, couponCode, count);
  254 + if(Objects.nonNull(redisLock)){
  255 + redisLock.unlock();
  256 + }
251 return couponCode; 257 return couponCode;
252 } 258 }
253 259
@@ -344,13 +350,22 @@ public class CouponServiceImpl implements ICouponService { @@ -344,13 +350,22 @@ public class CouponServiceImpl implements ICouponService {
344 } 350 }
345 351
346 352
347 - private void checkCanAcquire(Integer uid, String couponToken, CouponAndType couponAndType) { 353 + private RedisLock checkCanAcquire(Integer uid, String couponToken, CouponAndType couponAndType) {
348 // 验证该用户是否重复领取 354 // 验证该用户是否重复领取
349 UserCoupon userCoupon = userCouponMapper.selectByUidAndToken(uid, couponToken); 355 UserCoupon userCoupon = userCouponMapper.selectByUidAndToken(uid, couponToken);
  356 +
  357 + RedisLock redisLock = redisLockFactory.newLock(RedisKeyBuilder.newInstance()
  358 + .appendFixed("ufo:promotion:coupons:checkCanAcquire:")
  359 + .appendVar(uid + "-" + couponToken), 3, TimeUnit.SECONDS);
  360 + if (!redisLock.tryLock()) {
  361 + logger.info("{} checkCanAcquire fail, it already in the process", uid);
  362 + throw new UfoServiceException(400, "优惠券领取中");
  363 + }
350 if (userCoupon != null){ 364 if (userCoupon != null){
351 logger.warn("user has acquried this coupon before:{},{}", uid, couponToken); 365 logger.warn("user has acquried this coupon before:{},{}", uid, couponToken);
352 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_RECEIVED); 366 throw new ServiceException(ServiceError.PROMOTION_COUPON_HAS_RECEIVED);
353 } 367 }
  368 + return redisLock;
354 369
355 } 370 }
356 371