mysql 樂觀鎖 超賣 秒殺超賣解決方案

2021-10-18 20:55:31 字數 1077 閱讀 8809

方案一:redis事務處理(multi)

我們可以使用redis中的監聽(watch)方法,去監聽庫存數量,一旦庫存數量在其他客戶端發生改變,後續操作則會失敗。

watch key1 key2        監聽key1 key2有沒有變化,如果有變, 則事務取消

方案二:redis分布式鎖

分布式鎖確保只有乙個執行緒會操作庫存,明哥在redis文集中有過專門的整理

1加鎖(占個位置,後續的進不來):

setnx命令: 只在鍵key不存在的情況下,將鍵key的值設定為value 。若鍵key已經存在, 則不做任何動作。

2解鎖(用完了,就把位置讓出來):

del(key)

3鎖超時(萬一中間出現點意外,沒有解鎖,過幾秒會自動釋放)

expire(key,30)

方案三:redis佇列(rpoplpush的安全佇列)

把每一件商品都lpush到redis佇列中,利用lpop從佇列中去取

方案四:mysql層面優化update語句(湊數)

收到搶購請求後,對商品執行庫存 -1 操作。然後給使用者生成乙個訂單。

這系列操作中,併發問題在於:如果庫存為1,這時候有兩個使用者同一時間請求,那麼兩個程序同時select 到庫存數為1,並同時進行update -1操作,那麼相當於1件商品就賣出去了兩次。

那麼如何解決這個問題呢?很簡單。我們只需要把select庫存和update庫存-1這兩個操作放在1個事務裡,並且在select商品庫存的時候for update一下加上排他鎖。那麼就不存在兩人同時讀取到庫存1的可能了。第乙個人-1庫存,+1訂單,提交事務。第二人才能select到庫存。這時候庫存就是0了。自然而然就是搶購失敗。

上面是理論。實際操作中,有更簡單的辦法。那就是直接update 商品表 庫存-1 where id=商品id and 庫存!=0;然後獲取更新數量,如果不為1,就是搶購失敗。為1,就是搶購成功。這裡面保證併發安全的是資料庫的單條sql就是乙個事務的特性保證的。

優化方案1:將 庫存 字段 設為unsigned,當庫存為0時,因為字段不能為負數,將會返回false

優化方案2:使用mysql的事務,鎖住操作的行

方案五:樂觀鎖

秒殺超賣問題

秒殺問題其實就是併發讀寫的問題,需要解決超賣,效率等問題。可以使用redis將秒殺的資料進行快取,通過啟用定時任務,當redis中的庫存為0時將,快取持久化到資料庫中,並且將redis中的快取清除掉。service slf4j public class orderserviceimpl extend...

mysql 超賣 mysql 解決超賣問題的鎖分析

解決超賣問題,常見的方式,利用redis 的原子性去遞減 利用佇列,隊列入隊計數。或者直接打到mysql 層。由mysql 保證不超賣,有幾個玩法。利用屬性不一樣,挺有意思,記錄下。首先,mysql 隔離級別是rr,或者是序列,但是不可能用序列,太慢。其次,為什麼會出現超賣問題?因為這個select...

商品庫超賣的樂觀鎖

商品庫存的樂觀鎖實現。出現場景 避免商品出現超賣 即成功下單的訂單中商品的庫存數量大於商品現有的庫存量,則稱為商品超賣 的問題,核心技術是利用資料庫的事務鎖機制,即不允許同一商品的庫存記錄在同一時間被不同的兩個資料庫事務修改。功能實現 在前柔性事務介紹中所提到的,使用者在進行商品下單操作中,會進行一...