您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關SpringBoot中怎么實現一個商城秒殺系統,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
1.2 環境
window下:Zookeeper,Redis,rabbitmq-server。jdk1.8以上。
1.3 介紹
這里只做秒殺部分功能,其他功能不會涉及。項目運行后可訪問秒殺商品頁面
當用戶沒登陸,點擊詳情會跳轉到登陸頁面。
用戶登陸后可以查看商品的詳情并進行搶購。
注意,用戶對于一件商品只能搶購一次,進行第二次搶購時會被拒絕。當用戶搶購成功時會異步發送一封郵件給用戶。
主要邏輯就是以上。接下來看代碼
1.4 項目結構,api封裝一些枚舉和返回值,model主要是實體類和sql映射文件,service實現業務邏輯代碼。
1.5 顯示秒殺商品到頁面以及用戶的操作使用的還是MVC模式,不細講。主要看如實現高并發下的秒殺。
要細述的話,東西太多,如果想深入了解,可點擊上面的鏈接。
基本的秒殺邏輯如下,判斷用戶是否已經搶購過該商品,如果沒有則查詢待秒殺商品詳情,判斷該商品是否可以別秒殺,判斷依據為庫存是否足夠
如果符合條件,則該商品庫存減1,接著,再一次判斷扣減是否成功,如果扣減成功則生成秒殺成功的訂單,同時通知用戶秒殺成功的信息。
public Boolean killItem(Integer killId, Integer userId) throws Exception { Boolean result=false; //TODO:判斷當前用戶是否已經搶購過當前商品 if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){ //TODO:查詢待秒殺商品詳情 ItemKill itemKill=itemKillMapper.selectById(killId); //TODO:判斷是否可以被秒殺canKill=1? if (itemKill!=null && 1==itemKill.getCanKill() ){ //TODO:扣減庫存-減一 int res=itemKillMapper.updateKillItem(killId); //TODO:扣減是否成功?是-生成秒殺成功的訂單,同時通知用戶秒殺成功的消息 if (res>0){ commonRecordKillSuccessInfo(itemKill,userId); result=true; } } }else{ throw new Exception("您已經搶購過該商品了!"); } return result; }
代碼優化1:使用redis的分布式鎖,使用當前秒殺商品的id和當前用戶的id組成一個key,使用StringBuffer拼接,使用雪花算法生成一個value,存進redis中。
@Autowired private StringRedisTemplate stringRedisTemplate; /** * 商品秒殺核心業務邏輯的處理-redis的分布式鎖 * @param killId * @param userId * @return * @throws Exception */ @Override public Boolean killItemV3(Integer killId, Integer userId) throws Exception { Boolean result=false; if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){ //TODO:借助Redis的原子操作實現分布式鎖-對共享操作-資源進行控制 ValueOperations valueOperations=stringRedisTemplate.opsForValue(); final String key=new StringBuffer().append(killId).append(userId).append("-RedisLock").toString(); final String value=RandomUtil.generateOrderCode(); Boolean cacheRes=valueOperations.setIfAbsent(key,value); //luna腳本提供“分布式鎖服務”,就可以寫在一起 //TOOD:redis部署節點宕機了 if (cacheRes){ stringRedisTemplate.expire(key,30, TimeUnit.SECONDS); try { ItemKill itemKill=itemKillMapper.selectByIdV2(killId); if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){ int res=itemKillMapper.updateKillItemV2(killId); if (res>0){ commonRecordKillSuccessInfo(itemKill,userId); result=true; } } }catch (Exception e){ throw new Exception("還沒到搶購日期、已過了搶購時間或已被搶購完畢!"); }finally { if (value.equals(valueOperations.get(key).toString())){ stringRedisTemplate.delete(key); } } } }else{ throw new Exception("Redis-您已經搶購過該商品了!"); } return result; }
代碼優化2:將 Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS); 每隔30秒判斷當前用戶是否超時寫在了鎖外面,不會因為一次卡頓而影響整個程序。
@Autowired private RedissonClient redissonClient; /** * 商品秒殺核心業務邏輯的處理-redisson的分布式鎖 * @param killId * @param userId * @return * @throws Exception */ @Override public Boolean killItemV4(Integer killId, Integer userId) throws Exception { Boolean result=false; final String lockKey=new StringBuffer().append(killId).append(userId).append("-RedissonLock").toString(); RLock lock=redissonClient.getLock(lockKey); try { Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS); if (cacheRes){ //TODO:核心業務邏輯的處理 if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){ ItemKill itemKill=itemKillMapper.selectByIdV2(killId); if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){ int res=itemKillMapper.updateKillItemV2(killId); if (res>0){ commonRecordKillSuccessInfo(itemKill,userId); result=true; } } }else{ throw new Exception("redisson-您已經搶購過該商品了!"); } } }finally { lock.unlock(); //lock.forceUnlock(); } return result; }
代碼優化3:
@Autowired private CuratorFramework curatorFramework; private static final String pathPrefix="/kill/zkLock/"; /** * 商品秒殺核心業務邏輯的處理-基于ZooKeeper的分布式鎖 * @param killId * @param userId * @return * @throws Exception */ @Override public Boolean killItemV5(Integer killId, Integer userId) throws Exception { Boolean result=false; InterProcessMutex mutex=new InterProcessMutex(curatorFramework,pathPrefix+killId+userId+"-lock"); try { if (mutex.acquire(10L,TimeUnit.SECONDS)){ //TODO:核心業務邏輯 if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){ ItemKill itemKill=itemKillMapper.selectByIdV2(killId); if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){ int res=itemKillMapper.updateKillItemV2(killId); if (res>0){ commonRecordKillSuccessInfo(itemKill,userId); result=true; } } }else{ throw new Exception("zookeeper-您已經搶購過該商品了!"); } } }catch (Exception e){ throw new Exception("還沒到搶購日期、已過了搶購時間或已被搶購完畢!"); }finally { if (mutex!=null){ mutex.release(); } } return result; }
關于SpringBoot中怎么實現一個商城秒殺系統就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。