MySQL處理高併發,防止庫存超賣

来源:https://www.cnblogs.com/tpniu/archive/2017/12/28/8134998.html
-Advertisement-
Play Games

一般電子商務網站都會遇到如團購、秒殺、特價之類的活動,而這樣的活動有一個共同的特點就是訪問量激增、上千甚至上萬人搶購一個商品。然而,作為活動商品,庫存肯定是很有限的,如何控制庫存不讓出現超買,以防止造成不必要的損失是眾多電子商務網站程式員頭疼的問題,這同時也是最基本的問題。 ...


其實mysql處理高併發,防止庫存超賣的問題,在去年的時候,王總已經提過;但是很可惜,即使當時大家都聽懂了,但是在現實開發中,還是沒這方面的意識。今天就我的一些理解,整理一下這個問題,並希望以後這樣的課程能多點。

 

先來就庫存超賣的問題作描述:一般電子商務網站都會遇到如團購、秒殺、特價之類的活動,而這樣的活動有一個共同的特點就是訪問量激增、上千甚至上萬人搶購一個商品。然而,作為活動商品,庫存肯定是很有限的,如何控制庫存不讓出現超買,以防止造成不必要的損失是眾多電子商務網站程式員頭疼的問題,這同時也是最基本的問題。

 

從技術方面剖析,很多人肯定會想到事務,但是事務是控制庫存超賣的必要條件,但不是充分必要條件。

舉例:

總庫存:4個商品

請求人:a、1個商品 b、2個商品 c、3個商品

程式如下:

beginTranse(開啟事務)
try{
    $result = $dbca->query('select amount from s_store where postID = 12345');
    if(result->amount > 0){
        //quantity為請求減掉的庫存數量
        $dbca->query('update s_store set amount = amount - quantity where postID = 12345');
    }
}catch($e Exception){
    rollBack(回滾)
}
commit(提交事務)

以上代碼就是我們平時控制庫存寫的代碼了,大多數人都會這麼寫,看似問題不大,其實隱藏著巨大的漏洞。資料庫的訪問其實就是對磁碟文件的訪問,資料庫中的表其實就是保存在磁碟上的一個個文件,甚至一個文件包含了多張表。例如由於高併發,當前有三個用戶a、b、c三個用戶進入到了這個事務中,這個時候會產生一個共用鎖,所以在select的時候,這三個用戶查到的庫存數量都是4個,同時還要註意,mysql innodb查到的結果是有版本控制的,再其他用戶更新沒有commit之前(也就是沒有產生新版本之前),當前用戶查到的結果依然是就版本;

 

然後是update,假如這三個用戶同時到達update這裡,這個時候update更新語句會把併發串列化,也就是給同時到達這裡的是三個用戶排個序,一個一個執行,並生成排他鎖,在當前這個update語句commit之前,其他用戶等待執行,commit後,生成新的版本;這樣執行完後,庫存肯定為負數了。但是根據以上描述,我們修改一下代碼就不會出現超買現象了,代碼如下:

beginTranse(開啟事務)
try{
    //quantity為請求減掉的庫存數量    $dbca->query('update s_store set amount = amount - quantity where postID = 12345');
    $result = $dbca->query('select amount from s_store where postID = 12345');
    if(result->amount < 0){ throw new Exception('庫存不足'); } }catch($e Exception){ rollBack(回滾) } commit(提交事務)

另外,更簡潔的方法:

beginTranse(開啟事務)
try{
    //quantity為請求減掉的庫存數量    $dbca->query('update s_store set amount = amount - quantity where amount>=quantity and postID = 12345');
}catch($e Exception){
    rollBack(回滾)
}
commit(提交事務)

1、在秒殺的情況下,肯定不能如此高頻率的去讀寫資料庫,會嚴重造成性能問題的
必須使用緩存,將需要秒殺的商品放入緩存中,並使用鎖來處理其併發情況。當接到用戶秒殺提交訂單的情況下,先將商品數量遞減(加鎖/解鎖)後再進行其他方面的處理,處理失敗在將數據遞增1(加鎖/解鎖),否則表示交易成功。
當商品數量遞減到0時,表示商品秒殺完畢,拒絕其他用戶的請求。

 

2、這個肯定不能直接操作資料庫的,會掛的。直接讀庫寫庫對資料庫壓力太大,要用緩存。
把你要賣出的商品比如10個商品放到緩存中;然後在memcache里設置一個計數器來記錄請求數,這個請求書你可以以你要秒殺賣出的商品數為基數,比如你想賣出10個商品,只允許100個請求進來。那當計數器達到100的時候,後面進來的就顯示秒殺結束,這樣可以減輕你的伺服器的壓力。然後根據這100個請求,先付款的先得後付款的提示商品以秒殺完。

 

3、首先,多用戶併發修改同一條記錄時,肯定是後提交的用戶將覆蓋掉前者提交的結果了。

這個直接可以使用加鎖機制去解決,樂觀鎖或者悲觀鎖。

樂觀鎖,就是在資料庫設計一個版本號的欄位,每次修改都使其+1,這樣在提交時比對提交前的版本號就知道是不是併發提交了,但是有個缺點就是只能是應用中控制,如果有跨應用修改同一條數據樂觀鎖就沒辦法了,這個時候可以考慮悲觀鎖。


悲觀鎖,就是直接在資料庫層面將數據鎖死,類似於oralce中使用select xxxxx from xxxx where xx=xx for update,這樣其他線程將無法提交數據。


除了加鎖的方式也可以使用接收鎖定的方式,思路是在資料庫中設計一個狀態標識位,用戶在對數據進行修改前,將狀態標識位標識為正在編輯的狀態,這樣其他用戶要編輯此條記錄時系統將發現有其他用戶正在編輯,則拒絕其編輯的請求,類似於你在操作系統中某文件正在執行,然後你要修改該文件時,系統會提醒你該文件不可編輯或刪除。

 

4、不建議在資料庫層面加鎖,建議通過服務端的記憶體鎖(鎖主鍵)。當某個用戶要修改某個id的數據時,把要修改的id存入memcache,若其他用戶觸發修改此id的數據時,讀到memcache有這個id的值時,就阻止那個用戶修改。

 

5、實際應用中,並不是讓mysql去直面大併發讀寫,會藉助“外力”,比如緩存、利用主從庫實現讀寫分離、分表、使用隊列寫入等方法來降低併發讀寫。

 

本文鏈接http://blog.csdn.net/caomiao2006/article/details/38568825

更多參考內容:http://www.roncoo.com/article/index?tn=Mysql


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 問題背景: 一塊近似最小系統的控制小板,主要用於對電機,氣閥,集成液晶屏以及其他的部件控制。考慮電流會較大採用DC-DC穩壓管。 電路焊接完成後,最小系統正常工作。 問題: 加上液晶屏後,串口屏出現閃爍,5V電壓不穩。排除線路板線徑過細問題。 更換晶元後問題依然存在,但是穩壓晶元在某寶買的,還是擔心 ...
  • 原文:http://os.51cto.com/art/201609/518191.htm 經常使用Linux的開發人員或者運維人員,可能對configure->make->make install相當熟悉。事實上,這叫GNU構建系統,利用腳本和make程式在特定平臺上構建軟體。這種方式成為一種習慣, ...
  • awk是一種編程語言,主要用於在linux/unix下對文本和數據進行處理,是linux/unix下的一個工具。數據可以來自標準輸入、一個或多個文件,或其它命令的輸出。awk的處理文本和數據的方式:逐行掃描文件,預設從第一行到最後一行,尋找匹配的特定模式的行,併在這些行上進行你想要的操作。gawk是 ...
  • 背景 預設都是筆記本鍵盤才有Fn組合功能鍵,台式機很少有。今天領到的是聯想鍵盤,給我的台式機使用後F12很麻煩,必須Fn+F12才可以。 需求 恢復預設的F1~F12功能 方案 只需要下載驅動安裝: Windows 7 32-bit,Windows Vista 32-bit,Windows XP(3 ...
  • 常用功能差異 1. 鎖差異 : • Oracle鎖加在數據塊上 • InnoDB 是在索引上加鎖,所以MySQL鎖的粒度沒有Oracle 精細。 2. 導入導出 : • Oracle採用EXP /IMP ,EXPDP/IMPDP導入導出。 • MySQL採用mysqldump導出,導入可以採用管道或 ...
  • 操作系統 : CentOS7.3.1611_x64 go語言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目錄結構 目錄解析說明: influxdb 為源碼的主目錄 influxql 實現了InfluxDB查詢語言的解析器(源碼主目錄裡面引用的是i ...
  • 近期閱讀了一些深度學習在文本分類中的應用相關論文( " 論文筆記 " ),同時也參加了CCF 大數據與計算智能大賽(BDCI)2017的一個文本分類問題的比賽:讓AI當法官,並取得了最終評測第四名的成績(比賽的具體思路和代碼參見 " github項目repo " )。因此,本文總結了文本分類相關的深 ...
  • 此篇說明對應的kettle版本是6.1,實際使用時7.x應該也是一樣的。 一、 kettle開發流程(規範步驟,防止出錯) (一) Kettle設置檢查 如果不加一下配置項,數據轉換後中文會出現亂碼,很難處理。 本地連接資源庫:配置項 defaultFetchSize 500 useCursorFe ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...