引入redis防超抽带来的问题

业务

抽奖 每天每个用户只能抽3

想用redis来防同一用户并发超抽 极简代码如下

count = redisService.incr(key);
if(count > 3){
    //提示 抽奖次数已用完
    return;
}
doBusiness();

完善代码
设置过期时间

Long count = redisService.incr(key );
if(count != null && count == 1){
    //过期时间24小时
    redisService.expire(key, 24*60*60);
}

捕捉redis操作异常

Long count = null;
try{
    count = redisService.incr(key );
    if(count != null && count == 1){
        //过期时间24小时
        redisService.expire(key, 24*60*60); //若执行expire时失败了 则这个key就永不过期了
    }
}catch(Exception e){
    logger.error("redis操作异常", e);
}

若redis操作失败 从数据库中查询已抽奖次数

if(count == null){ //访问redis失败 从数据库中取抽奖次数
    drawCount = getDrawCountFromDb(mobile, today);    
}else{
    drawCount = count.intValue() - 1; 
}

考虑到数据库异常 抽奖次数还得减一

try{
    drawDbOper(); //抽奖数据库操作
}catch(Exception e){
    redisService.decr(key); //抽奖数减一
}

考虑到之前可能redis incr也失败了, 于是还得判断是否存在该key

catch(Exception e){
    String value = redisService.get(key);
    if(value != null){
        redisService.decr(key);
    }
}

考虑到redis decr也有可能失败 还得捕捉异常

catch(Exception e){
    try{
        String value = redisService.get(key);
        if(value != null){
            redisService.decr(key);
        }
    }catch(Exception e){
        logger.error("redis操作失败", e);
    }
}

TODO: 若之前redis incr成功 现在decr失败了怎么办?

若之前redis incr失败了, 则从数据库查询抽奖次数, 等之后redis恢复了, 因redis中未保存用户抽奖次数值, 用户还能再抽3次, 于是还得修改代码

boolean isRedisIncrSuccessful = true; //记录redis incr是否成功
if(count == null){ //访问redis失败 从数据库中取抽奖次数
    drawCount = getDrawCountFromDb(mobile, today);    
    isRedisIncrSuccessful = false;
}
try{
    drawDbOper(); //抽奖数据库操作
    //成功操作后 判断之前redis incr操作是否成功
    if(!isRedisIncrSuccessful){// 若之前redis incr操作失败
        // 补执行incr
        redisService.incr(key); //TODO: 捕捉异常
    }
}

引入了redis来防超抽后, 就好像娶错了人, 不得安生, 没完没了。

于是索性认为redis操作不会有异常, 数据库操作不会有异常, 这下代码清爽多了。

Long count = redisService.incr(key );
if(count > 3){
    //提示抽奖次数已满
    return result;
}
doBusiness();

你可能感兴趣的:(抽奖)