訂單並發處理--悲觀鎖和樂觀鎖、任務隊列以及訂單模塊開發流程


訂單模塊開發流程:

前端提交購買商品信息

1.在商品詳情頁面點擊購買按鈕,到達提交訂單頁面,頁面顯示收貨地址,商品信息,商品數量,總金額,支付方式等。然后點擊提交訂單按鈕,前端頁面將商品id、運費、總金額、總數量、支付方式等傳遞給后端的訂單視圖去創建訂單。

2.在生成訂單的時候需要去判斷庫存數量,如果庫存數量不夠,就返回商品庫存不足,整個創建訂單的流程,做成一個事務

3.在對庫存數量進行操作的地方使用鎖:樂觀鎖或者悲觀鎖

為什么要使用鎖

加入甲乙同時下單購買商品A,下單前查詢庫存數量都是15,在下單的時候,甲下單更快,買走了10件。而乙下單時,還是以庫存15來判斷,這樣就會出現數據錯誤。

在創建訂單時候,假設有人和你同時對商品數量進行操作,要保證數據是安全的,可以使用樂觀鎖。在更新商品數量的時候,需要判斷一下還是不是之前的數量,如果不是則說明數量被人改了,就會創建訂單失敗

解決思路

1.悲觀鎖    悲觀鎖是從讀取記錄那一刻就開始了

當查詢某條記錄時,就讓數據庫為該記錄加鎖,鎖住之后其他人無法操作該數據,其他事務要想獲取鎖,必須等原事務結束

select stock from tb_sku where id=1 for update;
SKU.objects.select_for_update().get(id=1)        #悲觀鎖

2.樂觀鎖      樂觀鎖是從UPDATE那一刻開始

樂觀鎖並不真正的鎖,而是在更新的時候判斷此時的庫存是否是之前查詢出的庫存,如果相同,表示數據沒被修改,可以更新庫存,否則不更新庫存

update tb_sku set stock=2 where id=1 and stock=7;    
SKU.objects.filter(id=1, stock=7).update(stock=2)   #更新之前做判斷

3.任務隊列

將下單的邏輯放到任務隊列中(如celery),將並行轉為串行,所有人排隊下單。比如開啟只有一個進程的Celery,一個訂單一個訂單的處理。
然后,我們現在解決了鎖的問題,全部請求采用“先進先出”的隊列方式來處理。那么新的問題來了,高並發的場景下,因為請求很多,很可能一瞬間將隊列內存“撐爆”,然后系統又陷入到了異常狀態。
或者設計一個極大的內存隊列,也是一種方案,但是,系統處理完一個隊列內請求的速度根本無法和瘋狂涌入隊列中的數目相比。
也就是說,隊列內的請求會越積累越多,最終Web系統平均響應時候還是會大幅下降,系統還是陷入異常。

是選擇悲觀鎖還是樂觀鎖

沖突比較少的時候,使用樂觀鎖。沖突比較多的時候,使用悲觀鎖
悲觀鎖的加鎖和解鎖都是需要消耗CPU資源的,所以在訂單並發少的情況使用樂觀鎖會是更好的選擇。

注意:在使用樂觀鎖的時候需要把MySQL數據庫的事務隔離級別更換成不可重復讀

MySQL數據庫事務隔離級別是可重復讀,這樣讀取的數據是一致的。改成不可重復讀,別的事務提交了,需要是能感知到數據修改了,這樣樂觀鎖才會起作用

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM