實際業務場景 在我們使用mysql的時候,如果不註意間隙鎖容易引起死鎖,最近分析一個業務場景就是間隙鎖導致的死鎖,業務抽象如下: 系統有一個批量新增業務資源的功能,實現邏輯如下(businnessid為非唯一索引): update 業務表 set isdeleted=1 where bussines ...
實際業務場景
在我們使用mysql的時候,如果不註意間隙鎖容易引起死鎖,最近分析一個業務場景就是間隙鎖導致的死鎖,業務抽象如下:
系統有一個批量新增業務資源的功能,實現邏輯如下(businnessid為非唯一索引):
update 業務表 set isdeleted=1 where bussinessid=123;
insert into 業務表
在併發場景下,以上邏輯產生了死鎖。
以下為死鎖具體分析以及還原死鎖產生過程,最後給出解決方案。
創建一張表
CREATE TABLE `lock_demo` (
`id` INT NOT NULL AUTO_INCREMENT,
`index` INT NOT NULL,
`name` VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `index` (`index`)
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
死鎖演示
事務一 |
事務二 |
update lock_demo set name='a' where index=1; |
|
|
update lock_demo set name='a' where index=2; 未卡住,間隙鎖之間不衝突 |
insert into lock_demo(id,`index`,name)values(1,1,'1'); 卡住,被事務二的間隙鎖鎖住 |
|
|
insert into lock_demo(id,`index`,name)values(2,2,'2'); 檢測到死鎖 |
具體步驟
步驟一
事務一
先更新一條記錄(不存在),不提交。
步驟二
事務二
更新一條記錄(不存在),不提交。
步驟三
事務一,執行一條新增語句,被事務二的間隙鎖鎖住
步驟四
事務二,執行一條新增語句,被事務一的間隙鎖鎖住,系統檢測到死鎖
解決方案
對於以上的業務,可以改寫sql避免死鎖
select id from 業務表 where bussinessid=123;
如果存在,
update 業務表 set isdeleted=1 where id in (xxx);
insert into 業務表