-
MySQL悲觀鎖
悲觀鎖:顧名思義,對待過來的請求持比較悲觀的態度,在處理請求的整個過程中,將數據鎖定,不允許其他進程/線程 修改
set autocommit=0; begin; select * from table where id = xx for update; //互斥鎖 //InnoDB 必須明確索引字段的值(查詢需走索引),否則會將整個表的數據都加鎖 ...... // 對數據進行操作 ...... commit;
當session1執行完 select * from table where field = xx for update; (field需要是索引字段) 的時候 就將那一行的數據鎖定了,此時 session2 再來執行 for update 或者 修改此條數據的操作的時候就會被阻塞
注:MySQL 悲觀鎖 雖然數據可以保證絕對正確,但是並發效率極低,一般不使用
-
MySQL樂觀鎖
樂觀鎖:顧名思義,對待過來的請求持比較樂觀的態度,先假設不會沖突,在提交更新的時候再去檢驗數據有沒有被其他進程修改過,如果中間有被其他進程修改過起沖突了,則返回錯誤
樂觀鎖的實現
-
版本控制 感興趣的話可以看一下MySQL的MVCC的實現原理(InnoDB默認的可重復讀隔離級別)
MVCC 原理 大致是這樣的:
- 數據庫有隱藏的創建版本和刪除版本的字段,每次開始事務的時候,事務版本號都會自增
- 新增數據的時候,在對應的創建版本號的地方填上 當前事務的版本號
- 更新數據的時候,將要更新的數據行的刪除版本號填上當前事務的版本號,然后插入一條新數據,創建版本號 填上 當前事務的版本號
- 刪除數據的時候,將要刪除的數據行的刪除版本號填上當前事務的版本號
- 查詢數據的時候,查詢 刪除版本號大於當前事務的版本號 或 創建版本號小於等於當前事務的版本號且刪除版本號為空
-
在where 條件中進行限制
// 在秒殺場景中的使用 1. 將庫存字段設置為 unsigned int 類型,庫存一直減,減到負數就直接報錯,應用程序捕獲這個錯誤進行處理這種方式依賴數據庫拋異常,算是數據庫設計的一種技巧,不算樂觀鎖 2. 更新庫存的時候,直接 update table set remain_amount = remain_amount - num where id = xx and remain_amount >= num // num 是一個 3. 結合 1,2
-
-
Redis 分布式鎖 參考 石杉的架構筆記--Redis分布式鎖的實現原理
-
原理大概是這樣的(Redis可能是一個集群,這里就當做是單機的場景,集群的話 加鎖只給master節點加鎖):
- Redis 是單進程單線程的,不涉及到鎖的問題,至於Redis的並發是借助 I/O多路復用( Epoll)實現
- 請求進來后先檢查 resource_str 這個hash類型的key存在不,如果不存在,則 hset resource_str client_str 1 ,然后設置一個過期時間;如果resource_str 存在,則 判斷 resource_str client_str 存在不,如果存在,延長過期時間;如果不存在則獲取一下 resource_str 的過期時間 time,然后client 進入循環等待time 秒 再重新 執行2 這個過程。
- 釋放鎖的時候,直接將 resource_str key 刪除即可
注:1. resource_str代表資源key client_str 代表客戶端字符串或者是session字符串
2. 上述情況如果 time過長,可以直接返回 超時
3. 在redis master實例宕機的時候,可能導致多個客戶端同時完成加鎖
-
-
Redis 分布式鎖的改進
- 上述的Redis 分布式鎖是基於一個 redis hash key 來實現的,這樣相當於串行化,並發效果也不好,在 石杉的架構筆記--分布式鎖高並發優化 中提到了一種辦法,分段加鎖。分段加鎖相當於是把之前的一個大鎖分成n個小鎖,每個小鎖管固定的一部分資源。當請求進來的時候就先利用3.1所述的Redis分布式鎖原理選一個資源鎖給當前客戶端加上,然后判斷商品庫存滿不滿足,如果滿足的話直接進行 創建訂單、減庫存、釋放鎖;如果不滿足的話,直接釋放當前的鎖,再給客戶端選下一個資源鎖加上 (這個選資源鎖的過程可以有一個隨機的算法,但是需要保證盡量不重復)。當所有的資源鎖都不滿足的話,就只能返回庫存不足了。
- 缺點:
- 實現比較復雜
- 如果每次下單的數量從一開始就一直大於 分段后的資源數,這種情況會到導致商品賣不完
注:1. 本文根據自己的理解所寫,如有不對的地方請及時反饋。
2. 如需轉載,請注明出處:https://www.cnblogs.com/zhuchenglin/p/12694937.html