比如商品 goods_id = 1
的商品庫存有10
件。100
個用戶同時購買,正常情況下只有10
個用戶能買到,其它用戶提示庫存不足建瘫。
方案一:
set autocommit = 0; begin; select sku from goods_sku where goods_id = 1; if(sku > 0){ update goods_sku set sku = sku - 1 where goods_id = 1; }else{ throw NoEnoughGoodsException(); } commit;
這種方案無法防止超賣。比如庫存還有1
尸折,兩個線程同時查到庫存都為1
后啰脚,做更新操作,這時庫存就為-1
了实夹。
方案二
set autocommit = 0; begin; select sku from goods_sku where goods_id = 1 for update; if(sku > 0){ update goods_sku set sku = sku - 1 where goods_id = 1; }else{ throw NoEnoughGoodsException(); } commit;
這種方案防止了超賣橄浓,但是每次 select 都加了排他鎖,阻塞其它線程讀亮航。
方案三
set autocommit = 0; begin; int affected = update goods_sku set sku = sku - 1 where goods_id = 1 and sku > 0; if( affected != 1){ throw NoEnoughGoodsException(); } commit;
這種方案解決了上面的問題荸实,但是對數(shù)據(jù)庫的壓力還是很大。
方案四
使用Redis等NoSQL數(shù)據(jù)庫塞赂。