一、問題描述
最近工作中發現了一個系統問題,涉及到關於 mysql for update 排他鎖,沒有阻塞其他事務的問題。
主要的業務爲多個內配箱子入庫回傳修改箱子、內配單狀態,內配單狀態爲配貨完成狀態,沒有被修改爲上架完成狀態。
一個內配單可能存在多個商品,一個內配單發貨可能會發不同的箱子,每個箱子可能包含不同的內配單的商品。即內配單與箱子的關係是多對多。
二、原因分析
數據庫的隔離級別:讀已提交
2.1 箱子入庫回傳流程
select
c.id as id
from
table_c c
where
c.id in (xxx, xxx)
and not exists (
select
1
from
table_s s,
table_b b
where
s.chuku_id = c.id
and s.box_id = b.id
and b.work_statue != '4'
) for
update
2.2 FOR UPDATE 語句的用法
在 MySQL 中,SELECT ... FOR UPDATE
語句是一種鎖定讀取操作,它鎖定語句返回的所有行,以防止其他事務在這些行上執行 UPDATE
或 DELETE
操作直到當前事務提交。
以下是 FOR UPDATE
鎖定的一些關鍵點: 鎖定範圍:
FOR UPDATE
會對查詢結果中的所有行設置排他鎖(X鎖)。- 如果查詢中包含了 WHERE 子句,那麼只有滿足條件的行會被鎖定。
- 如果查詢中包含了 join 操作,那麼涉及的所有表的相關行都會被鎖定。 鎖定行爲:
- 其他事務不能對這些行執行
UPDATE
或DELETE
操作,直到當前事務提交。 - 其他事務仍然可以讀取這些行,因爲
SELECT ... FOR UPDATE
不會阻止共享鎖(S鎖)。 鎖定持續時間: - 鎖定會一直持續到事務結束(提交或回滾)。 死鎖風險:
- 使用
FOR UPDATE
時,如果兩個事務嘗試鎖定對方已經鎖定的行,可能會導致死鎖。 使用限制: FOR UPDATE
只能在支持行級鎖的存儲引擎(如 InnoDB)上使用。- 要使用
FOR UPDATE
,必須開啓一個事務(使用BEGIN
或START TRANSACTION
)。
例如:
BEGIN;
SELECT * FROM your_table WHERE condition FOR UPDATE;
UPDATE your_table SET column = value WHERE condition;
COMMIT;
上面的例子中,SELECT ... FOR UPDATE
語句會鎖定所有滿足 WHERE condition
的行,然後 UPDATE
語句可以安全地對這些行進行修改。
請記住,使用 FOR UPDATE
時要謹慎,因爲它可能會影響併發性和性能。只在必要時使用它,並確保事務儘可能短且高效。
2.3 原因總結
如果內配箱子涉及到相同的內配單,且存在箱子包含多個內配單,且先於其他箱子的事務(只包含一個內配單)執行 for update 的SQL語句,那麼後邊的事務會出現不會被阻塞的問題。
如果多個箱子都包含相同內配單號,且只有一個,那麼多個事務同時執行 for update 語句時就會阻塞(正確)。 一句話描述問題,執行 for update SQL語句時,想要達到多個事務阻塞效果,必須兩個事務執行select...for update 數據的查詢結果一樣。
三、解決方案
1、針對箱子入庫回傳增加分佈式鎖方案流程
- 箱子入庫回傳時,先查詢箱子對應的內配單號
- 然後將內配單按照升序排序,分別設置redis分佈式鎖
- 全部加鎖成功之後,處理業務
- 如果任何一個內配單加鎖失敗,說明被其他箱子加鎖了,拋出異常,重試
優點:僅僅改動箱子入庫回傳這塊代碼 缺點:需要開發代碼,上線測試
2、修改 for update 的SQL,增加獨立的加鎖語句
修改邏輯:
- 將箱子對應的內配單ID 進行 for update的查詢,且不加其他條件,確保可以其他可以鎖定住其他事務的查詢
select
c.id as id
from
table_c c
where
c.id in (xxx, xxx) for
update
- 再查詢對應的已完成的箱子信息
select
c.id as id
from
table_c c
where
c.id in (xxx, xxx)
and not exists (
select
1
from
table_s s,
table_b b
where
s.chuku_id = c.id
and s.box_id = b.id
and b.work_statue != '4'
)
優點:不用增加分佈式鎖 缺點:增加了兩次數據庫查詢,一次是利用 for update 語句負責加鎖,另一次是查詢滿足條件的數據,可能會影響處理效率。
參考: https://dogslee.top/2021/08/25/%E8%AE%BE%E7%BD%AEMySQL%E7%9A%84%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB/ https://www.51cto.com/article/745157.html