1. 程式人生 > >redis的活動倒計時秒殺問題

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);//活動狀態批量更新為 進行中

}

這個方案比較第二種,就是少了手動記憶體排序這一步驟,提升效率。