1、在設計公司的庫存架構的時候,出現了問題,當處理無座商品的時候,發現,回滾邏輯有問題,具體的邏輯為:
比如如果庫存設置為1 ,則
(1) 用戶1 下單成功,庫存-1
(2)用戶2下單因為庫存 是0所以 下單失敗,開始回滾,回滾的時候+1,導致目前的庫存為 1(實際上這個庫存已經被用戶1買走了)
(3)用戶3 下單成功 ,庫存-1
最后:導致庫存1 賣了2次,
原因分析:
回滾邏輯沒有顯示訂單號,應該嚴格按照訂單號回滾,否則會把別人的庫存回滾掉;
大麥的邏輯設置:
首先第一步:
假設庫存總量為total_count,本次用戶下單的數量為10;
數據庫有3列,總 total_count,已售: sale_count,剩余 marging_count;
這些都放在一個事務中
try{
1、查詢訂單庫存,如果庫存不足直接返回 查詢的條件唯一(比如按照訂單號)
2、將庫存鎖定比如 1是未鎖定,2是鎖定 則 設置當前的行為鎖定狀態;
update recrod set status=2 where status=1 and 條件;
3、如果需要修改的庫存有多條,對需要修改的庫存進行排序(防止死鎖)
4、逐行設置庫存:
update sale_count+10 ,margin_count-10 where 條件+status=2 and sale_count-10>=0;
} catch(Exception e){
}
之所以如此設置:
1、全部放在一個事務中,方便異常回滾,
2、使用一個status鎖定狀態,因為mysql是行鎖,保證事務並發處理的時候只有個線程可以往后走,后面的線程會等待,處理一條數據,
3、指定一個唯一條件,比如按照訂單號回滾,如果訂單號不滿足直接退出,防止回滾別人的庫存
4、設置庫存的時候,需要先進行排序,讓線程順序執行,防止死鎖,舉個栗子:
如果不排序:A,B兩個線程 ,回滾庫存 ,如果第一個A線程扣減了X1行,下一步執行Y1行,
但另一個線程B,扣減了Y1,下一步需要扣減X1行,這時候,
A線程占着X1行,需要等待B線程釋放Y1行,
而同時B線程占着Y1行,等待着A線程釋放X1行,
產生了死鎖
所以必須要排序;
5、扣減的時候執行 條件添加:sale_count-10>=0; 保證即使某個地方有問題,也不會扣減為負數;
問題:1、sale_count-10>=0; 不是小於=0;
是的;
2、排序如何排序,根據什么條件排序 根據票品的ID進行排序,保證順序;
3、我們的設置狀態是鎖定狀態?那也就是每個庫存都要設置一個是否鎖定的狀態? 還是專門設計一張表,鎖定狀態,賣座的優惠券發券如何設計
可以加一張新表把狀態放進來;