背景:
眾所周知,高並發情況下,對於庫存的操作要格外小心,處理不當可能導致庫存超扣,帶來不必要的損失。
超扣原因:多並發一起讀,發現庫存均為1,然后各扣各的,最終庫存為負。
方法:
1. 悲觀鎖:認為要超扣,提前防止
select num from product where xxx for update; 只允許單線程讀取。
缺點:阻塞問題,導致其他線程等待
2.樂觀鎖:認為不會超扣,更新時再驗證
update product set num = num - n where id=xxx and num > n; 保證減后得正值
優點:大量讀情況,減少鎖開銷,提高系統吞吐量,
但並發很高。經常發生沖突重試則不如使用悲觀鎖
3.鎖:比如redis鎖,java synchronized
setNX(key, id, expireTime); 利用單線程redis的原子操作
優點 : 減輕mysql壓力,性能快。
缺點:數據一致性,需要更多代碼維護。可以采用雙重緩存,或者隊列補償方式實現最終一致性
4.阻塞隊列,僅適用於秒殺這種不連續請求的業務。將請求入隊列,由單個消費者順序執行。
缺點:局限於業務,不能實時反饋結果。