分布式锁实现中奖接口代码片

70 阅读1分钟
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;


@ApolloJsonValue("${lottery.list:[{"name":"vip","code":"1001","count":"10"}]}")
private List<LotteryListVo> lotteryList;
@Resource
private BibleLotteryDao bibleLotteryDao;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource(name = "redissonClient")
private RedissonClient redissonClient;

public void winLottery(LotteryWinRequest request, String userId, Integer count) throws BusinessException {
    // 奖品
    String code = request.getCode();
    String packageName = request.getPackageName();

    String redisLockKey = String.format(BibleConstant.LOTTERY_LIST_LOCK_PACKAGE_NAME, packageName, code);
    String key = String.format(BibleConstant.LOTTERY_LIST_PACKAGE_NAME, packageName, code);
    RLock lock = redissonClient.getLock(redisLockKey);
    try {
        boolean lockAcquired = lock.tryLock(100, 10000, TimeUnit.MILLISECONDS);
        if (!lockAcquired) {
            log.info("Lottery Win Lock not acquired redisKey", key);
            throw new BusinessRuntimeException(ErrorCode.GET_REDISSON_LOCK_ERROR);
        }

        Long startTime = DateUtils.getCurrentTime();
        String redisValue = stringRedisTemplate.opsForValue().get(key);
        Integer nowAvail = 0;
        if (StringUtils.isEmpty(redisValue)) {
            Integer nowCount = bibleLotteryDao.selectCountByCode(packageName, code);
            nowAvail = count - nowCount;
        } else {
            nowAvail = Integer.valueOf(redisValue);
        }
        boolean win = nowAvail > 0;
        if (win) {
            --nowAvail;
        }
        // 插入中奖记录
        BibleLotteryPO bibleLotteryPO = new BibleLotteryPO();
        bibleLotteryPO.setUserId(userId);
        bibleLotteryPO.setClientId(request.getClientId());
        bibleLotteryPO.setPackageName(request.getPackageName());
        bibleLotteryPO.setCode(code);
        bibleLotteryPO.setTotalCount(count);
        bibleLotteryPO.setAvailableCount(nowAvail);
        bibleLotteryPO.setIsWin(win ? 1 : 0);
        bibleLotteryPO.setCreateTime(startTime);
        bibleLotteryPO.setUpdateTime(DateUtils.getCurrentTime());
        bibleLotteryDao.insert(bibleLotteryPO);
        if (win) {
            stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(nowAvail), 1, TimeUnit.HOURS);
        } else {
            throw new BusinessException(ErrorCode.LOTTERY_COUNT_LIMIT);
        }
    } catch (InterruptedException e) {
        log.error("Lottery Win Lock get InterruptedException redisKey:{},e:{}", key, e);
        throw new BusinessRuntimeException(ErrorCode.GET_REDISSON_LOCK_ERROR);
    } finally {
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
        log.info("Lottery Win Lock get finally unlock redisKey:{}" + key);
    }
}