redis的活动倒计时秒杀问题

版权声明:本文为博主原创文章,转载需标明出处哦 ^-^。 https://blog.csdn.net/qq_33101675/article/details/83118461

我们知道电商里有很多场景,就是活动倒计时的秒杀问题,比如:明天10点开始抢购,倒计时2分钟等,那么这个到底有多精确呢?是不是2分钟时间刚刚到活动就准时开始呢?我们今天先来说下倒计时,改天说秒杀问题。

我说一下做法,这里有三种方案,是我思考出来的,可能不对,也可能有更好的方案,仅供参考吧。

首先还有一张表,记录着活动商品,里面有活动的状态、价格,标签,最重要的是有活动的开始时间

1、新建一个缓存,key为固定的,查询活动商品表,把所有的活动待开始的商品,放进该缓存里。然后写个定时任务,可以每5秒(如果要很精准的话,那就每秒去查询该缓存),去查询该缓存key,获取到所有的待开始的商品list,遍历这个list,拿每条数据的开始时间与当前时间相比,如果开始时间 <= new Date()时,表明该商品活动已经开始了,List<Integer> needUpdates = new ArrayList<>();那就用needUpdates.add(该商品ID),用来最后批量更新的,把这些商品的状态由 未开始 批量更新为 进行中;更新DB成功后,要将刚刚活动已开始的商品,从缓存中移除掉,由于redis没有提供按照index来操作list中的某一条数据,那我们的做法是,jedis.del(key),然后再查询DB,把所有的活动待开始的商品,放进该缓存里,全删全增。

List<Dto> list =  jedis.get(key);

for(Dto dto : list){

if(dto.getStartTime().getTime() <= new Date().getTime()){//商品已达到活动时间了

needUpdates.add(dto.getId());

contiune;

}

contiune;

}

if(Collentions.isNotEmpty(needUpdates)){

mapper.updateBatch(needUpdates);//活动状态批量更新为 进行中

jedis.del(key);

jedis.set(key,"DB里所有待开始的活动商品")

}

2、上面的做法,可以满足需求,但是要全删全增缓存,为了避免这种做法,我们可以借助redis中list类型里的rpop和lpop来做。新建一个缓存,key是固定的,查询活动商品表,把所有的活动待开始的商品,按照活动开始时间进行从大到小排序,放进该缓存里。然后开启一个定时任务,每5秒执行一次,List<Dto> list =  jedis.get(key); 得到排序好的list。

List<Integer> needUpdates = new ArrayList<>();

for(Dto dto : list){

if(dto.getStartTime().getTime() <= new Date().getTime()){//商品已达到活动时间了

jedis.Lpop(key);//移出并获取列表的第一个元素,从缓存中移除该条数据

needUpdates.add(dto.getId());

contiune;

}else{//因为是按开始时间从大到小排序的,所以上面的条件不满足,下面的数据也不需要判断了

break;

}

}

if(Collentions.isNotEmpty(needUpdates)){

mapper.updateBatch(needUpdates);//活动状态批量更新为 进行中

}

这样的话,定时任务里就不用全删和全增数据了,但是在后台,新增或更新活动商品的时候,还是要删除缓存,查询数据并按开始时间排序,放进缓存的,也需要全删全增。

3、与第二种类似,只不过这里借助redis里的有序集合,这样的话,就不用我们自己按照时间排序了,让redis来帮我们排序,直接上伪代码吧。

后台新增或者更新活动商品的时候

ZADD key 开始时间的毫秒数1  dto1(数据)

ZADD key 开始时间的毫秒数2  dto2(数据)

ZADD key 开始时间的毫秒数3  dto3(数据)。。。

这样存到redis里,redis就会自动帮我们排序了,把 开始时间的毫秒数 最大的放在第一位

然后起一个定时任务,每5秒执行一次,List<Dto> list =  jedis.get(key);

for(Dto dto : list){

if(dto.getStartTime().getTime() <= new Date().getTime()){//商品已达到活动时间了

zremrangebyrank key 0 0;//从缓存里移除掉第一个数据

needUpdates.add(dto.getId());

contiune;

}else{//因为是按开始时间从大到小排序的,所以上面的条件不满足,下面的数据也不需要判断了

break;

}

}

if(Collentions.isNotEmpty(needUpdates)){

mapper.updateBatch(needUpdates);//活动状态批量更新为 进行中

}

这个方案比较第二种,就是少了手动内存排序这一步骤,提升效率。
 

猜你喜欢

转载自blog.csdn.net/zht741322694/article/details/83756675