Mysq詳細講解如何解決庫存並發問題
面臨的問題
長話短說,假設我們現在面臨以下需求
- 商品的庫存有兩千,賣完為止
- 某商品本日的售賣隻允許賣出一百,賣完為止
如何實現
我提出的方案也很簡單,使用樂觀鎖的方式。
以下是具體的方案
-- stock: 當前庫存數 number:扣減的數量 -- UPDATE t SET stock -= number WHERE stock >= number
外加上事務,便可以實現一個基本的庫存扣減操作。大部分情況下,無需擔心所謂的“並發問題”。事務具有的特性,會在此處幫你解決的掉這個大難題。
(簡單的說:事務會在執行 非查詢 的操作的時候,會實現類似鎖的功能。直到前面的事物提交或者回滾之前,後續的操作都會被掛住)
需求具體實現的方案
1.商品的庫存兩千,賣完為止
其實從理論上,想解決這個問題,隻依靠上文之中的update語句便可以完成。
具體步驟如下:
- 執行UPDATE 語句,查看其結果 。
- 若是,則執行後續操作
- 若否,代碼回滾
具體代碼如下
//開始事務 beginTransaction(); // 扣減庫存前的業務 // 執行扣減庫存操作 boolean reduceStockSuccess = reduceStock(); if(!reduceStockSuccess){ //扣減庫存失敗,代碼回滾 rollback(); return; } // 執行扣減庫存後的業務操作 //記錄庫存 writeRecod(); //提交事務 commit(); return;
雖然,程序其實如此便可。但是從個人的角度去看,我還是建議大傢多做一點校驗,以減少UPDATE程序運行次數。
就比如說,我們可以在前面加一個查詢當前庫存數量代碼。
主要的目的在於,雖然這個校驗代碼,不能說百分百的解決問題 ,擋住所有的流量。但是卻可以擋住大部分無意義的流量,調用UPDATE的次數。
簡單來說,就跟我們小時候玩坦克大戰一樣,雖然我們玩傢不能擋住所有的進攻者。但也並不是隨隨便便誰都可以往我們傢基地開炮。
//開始事務 beginTransaction(); // 扣減庫存前的業務 int stock = getStock(); if(stock <= 0 ){ //庫存不足,退出程序 rollback(); return; } // 執行扣減庫存操作 boolean reduceStockSuccess = reduceStock(); if(!reduceStockSuccess){ //扣減庫存失敗,代碼回滾 rollback(); return; } // 執行扣減庫存後的業務操作 //記錄庫存 writeRecod(); //提交事務 commit(); return;
2 . 日庫存數一百 , 賣完為止
該需求相比1來說,問題在於。單從庫存表,記錄表來說。除非我們在新增到記錄表的SQL裡面將每日庫存數100接入。否則,我們無法通過事務與SQL來幫我們解決並發問題。
但是我們又不可能在記錄購買信息的代碼內,每日庫存數100的邏輯耦合進去。
因此,這個問題對於MYSQL來說是個死局。
若想單靠MYSQL之力若想破局,我們隻能依靠將每日庫存數的這個邏輯,專門設計一張數據表。
如設計一張商品每日購買數量記錄表記錄某個商品每日被購買的數量。
在每次購買的時候都更新一下本日購買的數量
UPDATE day_t SET day_stock += number WHERE day_stock + number <= 100
雖然能解決需求問題,但是表現出來的問題依然是業務耦合進公關表內。
- 每日購買數量表,不應當僅僅為每日購買上限服務。當前的解決問題的方案,等同於解決問題的同時又制造瞭一個差不多的問題。隻是一個問題轉移到瞭其他部分出問題
- 即使我們為該需求專門創建一張表,但是隨著後續的數據表越來越多,程序的管理性卻越來越差,比如後續還會出現周限制,月限制,年限制等等等等。
總結
現在我們可以看出,使用MYSQL的方式雖然簡單,但是卻有著非常大的局限性。
但這裡也並不是說某些方案一定好,卻也一定差。
主要看當前的業務,MYSQL的方式,適用於最底層。適合完成某個業務最原始的功能。
到此這篇關於Mysq詳細講解如何解決庫存並發問題的文章就介紹到這瞭,更多相關Mysq庫存並發內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- MySQL悲觀鎖與樂觀鎖的實現方案
- 一文搞懂MySQL XA如何實現分佈式事務
- 如何使用Redis實現電商系統的庫存扣減
- MySQL事務的ACID特性以及並發問題方案
- Redis解決優惠券秒殺應用案例