當前位置:
首頁 > 知識 > 高並發下的下單功能設計

高並發下的下單功能設計

功能需求:設計一個秒殺系統初始方案

商品表設計:熱銷商品提供給用戶秒殺,有初始庫存。

@EntitypublicclassSecKillGoodsimplementsSerializable{@IdprivateStringid;/*** 剩餘庫存*/private Integer remainNum;/*** 秒殺商品名稱*/privateStringgoodsName;}

秒殺訂單表設計:記錄秒殺成功的訂單情況

@Entitypublic class SecKillOrder implements Serializable {@Id@GenericGenerator(name ="PKUUID", strategy ="uuid2")@GeneratedValue(generator ="PKUUID")@Column(length =36) private String id;//用戶名稱privateStringconsumer;//秒殺產品編號privateStringgoodsId;//購買數量privateIntegernum;}

Dao設計:主要就是一個減少庫存方法,其他CRUD使用JPA自帶的方法

publicinterfaceSecKillGoodsDaoextendsJpaRepository{@Query("update SecKillGoods g set g.remainNum = g.remainNum - ?2 where g.id=?1")@Modifying(clearAutomatically =true)@TransactionalintreduceStock(String id,Integer remainNum);}

數據初始化以及提供保存訂單的操作:

@ServicepublicclassSecKillService{@AutowiredSecKillGoodsDao secKillGoodsDao;@AutowiredSecKillOrderDao secKillOrderDao;/** * 程序啟動時: * 初始化秒殺商品,清空訂單數據 */@PostConstructpublicvoidinitSecKillEntity(){ secKillGoodsDao.deleteAll(); secKillOrderDao.deleteAll(); SecKillGoods secKillGoods =newSecKillGoods(); secKillGoods.setId("123456"); secKillGoods.setGoodsName("秒殺產品"); secKillGoods.setRemainNum(10); secKillGoodsDao.save(secKillGoods); }/** * 購買成功,保存訂單 *@paramconsumer *@paramgoodsId *@paramnum */publicvoidgenerateOrder(String consumer, String goodsId, Integer num){ secKillOrderDao.save(newSecKillOrder(consumer,goodsId,num)); }}

下面就是controller層的設計

@ControllerpublicclassSecKillController{@AutowiredSecKillGoodsDao secKillGoodsDao;@AutowiredSecKillService secKillService;/*** 普通寫法* @param consumer* @param goodsId* @return*/@RequestMapping("/seckill.html")@ResponseBodypublicStringSecKill(Stringconsumer,StringgoodsId,Integernum) throws InterruptedException {//查找出用戶要買的商品SecKillGoods goods = secKillGoodsDao.findOne(goodsId);//如果有這麼多庫存if(goods.getRemainNum()>=num){//模擬網路延時Thread.sleep(1000);//先減去庫存secKillGoodsDao.reduceStock(num);//保存訂單secKillService.generateOrder(consumer,goodsId,num);return"購買成功"; }return"購買失敗,庫存不足"; }}

上面是全部的基礎準備,下面使用一個單元測試方法,模擬高並發下,很多人來購買同一個熱門商品的情況。

@ControllerpublicclassSecKillSimulationOpController{finalStringtakeOrderUrl ="http://127.0.0.1:8080/seckill.html";/*** 模擬並發下單*/@RequestMapping("/simulationCocurrentTakeOrder")@ResponseBodypublicStringsimulationCocurrentTakeOrder() {//httpClient工廠finalSimpleClientHttpRequestFactory httpRequestFactory =newSimpleClientHttpRequestFactory();//開50個線程模擬並發秒殺下單for(inti =; i

訪問localhost:8080/simulationCocurrentTakeOrder,就可以測試了

預期情況:因為我們只對秒殺商品(123456)初始化了10件,理想情況當然是庫存減少到0,訂單表也只有10條記錄。

實際情況:訂單表記錄

商品表記錄

下面分析一下為啥會出現超庫存的情況:

因為多個請求訪問,僅僅是使用dao查詢了一次資料庫有沒有庫存,但是比較惡劣的情況是很多人都查到了有庫存,這個時候因為程序處理的延遲,沒有及時的減少庫存,那就出現了臟讀。如何在設計上避免呢?最笨的方法是對SecKillController的seckill方法做同步,每次只有一個人能下單。但是太影響性能了,下單變成了同步操作。

@RequestMapping("/seckill.html")@ResponseBodypublic synchronized String SecKill改進方案

根據多線程編程的規範,提倡對共享資源加鎖,在最有可能出現並發爭搶的情況下加同步塊的思想。應該同一時刻只有一個線程去減少庫存。但是這裡給出一個最好的方案,就是利用Oracle,MySQL的行級鎖–同一時間只有一個線程能夠操作同一行記錄,對SecKillGoodsDao進行改造:

publicinterfaceSecKillGoodsDaoextendsJpaRepository{@Query("update SecKillGoods g set g.remainNum = g.remainNum - ?2 where g.id=?1 and g.remainNum>0")@Modifying(clearAutomatically =true)@TransactionalintreduceStock(String id,Integer remainNum);}

僅僅是加了一個and,卻造成了很大的改變,返回int值代表的是影響的行數,對應到controller做出相應的判斷。

@RequestMapping("/seckill.html")@ResponseBodypublicStringSecKill(Stringconsumer,StringgoodsId,Integernum) throws InterruptedException {//查找出用戶要買的商品SecKillGoods goods = secKillGoodsDao.findOne(goodsId);//如果有這麼多庫存if(goods.getRemainNum()>=num){//模擬網路延時Thread.sleep(1000);if(goods.getRemainNum()>) {//先減去庫存inti = secKillGoodsDao.reduceStock(goodsId,num);if(i!=) {//保存訂單secKillService.generateOrder(consumer, goodsId,num);return"購買成功"; }else{return"購買失敗,庫存不足"; } }else{return"購買失敗,庫存不足"; } }return"購買失敗,庫存不足"; }

在看看運行情況

訂單表:

在高並發問題下的秒殺情況,即使存在網路延時,也得到了保障。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 PHP技術大全 的精彩文章:

Uber醜聞不斷,被曝將問題車租給司機
VIM使用技巧及快捷操作
MySQL性能優化的最佳20 條經驗
php如何解決中文亂碼問題?
一些MongoDB的坑

TAG:PHP技術大全 |

您可能感興趣

設計書單 | 並不是所有的設計師都能設計出好的字體
高腰的設計上窄下寬,打造出完美的身材線條
設計書單 | 設計不可能倒退到手工時代,但越來越多的設計師開始回歸最基本的狀態
再不開發腦洞,在設計界都混不下去了!
王俊凱設計的球鞋終於要發售了!可能極其限量!
設計,重「心」出發
除了上下床難,兒童房還可以這麼設計~
設計不可能倒退到手工時代,但越來越多的設計師開始回歸最基本的狀態
6個海報設計思路,初學者掌握了也能做出高大上作品!
三星發布能隱形的電視,超薄設計,掛起來還可以當畫框!
魅藍首款高端機魅藍E3售價曝光;設計終究還是向做出了市場妥協
遍游世界的他,用隨性不羈發掘設計的無限可能
以後你可能會穿上自己設計的耐克球衣
極具冷艷與大膽設計!這可能是顏值最高的魅藍手機
如何設計高性能低側電流感應設計中的印刷電路板
將電氣設計和機械設計融合在一起能給客戶帶來哪些價值
中國設計的火箭炮性能都要趕上導彈的水平了,俄羅斯後悔不已
這些鞋櫃設計太逆天了,顏值與實用並存,收納功能強大
又一款AI智能音箱發布 懸浮式設計!
海面上漂浮的垃圾,在設計師的雙手上也能變成一款新型運動鞋