在初學者從源碼理解MySQL死鎖問題中介紹了使用調試 MySQL 源碼的方式來查看死鎖的過程,這篇文章來講講一個常見的案例。
這次我們講一段唯一索引 S 鎖與 X 鎖的愛恨情仇
十年的山陰網站建設經驗,針對設計、前端、開發、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。成都全網營銷推廣的優勢是能夠根據用戶設備顯示端的尺寸不同,自動調整山陰建站的顯示方式,使網站能夠適用不同顯示終端,在瀏覽器中調整網站的寬度,無論在任何一種瀏覽器上瀏覽網站,都能展現優雅布局與設計,從而大程度地提升瀏覽體驗。創新互聯從事“山陰網站設計”,“山陰網站推廣”以來,每個客戶項目都認真落實執行。
我們來看一個簡化過的例子
# 構造數據 CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10), `level` int(11), PRIMARY KEY (`id`), UNIQUE KEY `uk_name` (`name`) ); INSERT INTO `t1` (`name`, `level`) VALUES ('A',0); # 出現問題的sql語句如下,并發情況下就會出現死鎖 INSERT ignore INTO `t1` (`name`, `level`) VALUES ('A',0); update t1 set level = 1 where name = "A";
我們用之前介紹過的源碼分析方式,先來看下這兩條語句分別加什么鎖,然后分析死鎖形成的過程。
第一條語句
INSERT ignore INTO t1 (name, level) VALUES ('A',0);
在調試中得到的結果如下
可以看到這條語句對唯一鍵 uk_name 加共享鎖(S鎖),而且成功。
第二條語句
update t1 set level = 1 where name = "A";
通過唯一鍵更新數據庫字段。
這種情況在之前的文章已經介紹過,會對唯一索引加 X 鎖,然后對主鍵索引加 X 鎖
這樣就可以非常輕松的復現死鎖的問題了,步驟如下
1.開啟兩個 session,分別 begin
2.session1 執行INSERT ignore INTO t1 (name, level) VALUES ('A',0);
3.session2 執行INSERT ignore INTO t1 (name, level) VALUES ('A',0);
4.session1 執行update t1 set level = 1 where name = "A"; 進入等待狀態
5.session2 執行update t1 set level = 1 where name = "A";,死鎖產生,被回滾,同時事務 1 執行成功
詳細的鎖狀態變化如下
t1 | t2 | 備注 |
---|---|---|
INSERT IGNORE INTO | - | t1成功獲得uk的S鎖 DB_SUCCESS |
- | INSERT IGNORE INTO | t2成功獲得uk的S鎖 DB_SUCCESS |
UPDATE | - | t1嘗試獲得uk的X鎖,但沒有成功,處于等待狀態 DB_LOCK_WAIT |
- | UPDATE | t2嘗試獲得uk的X鎖,發現死鎖產生 DB_DEADLOCK |
- | Deadlock | t2釋放S鎖 |
成功 | - | - |
死鎖日志如下:
LATEST DETECTED DEADLOCK ------------------------ 181208 23:00:52 *** (1) TRANSACTION: TRANSACTION 53A7, ACTIVE 162 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s) MySQL thread id 12, OS thread handle 0x700010522000, query id 1424 localhost root Updating update t1 set level = 1 where name = "A" *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 89 page no 4 n bits 72 index `uk_name` of table `lock_demo2`.`t1` trx id 53A7 lock_mode X locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 1; hex 41; asc A;; 1: len 4; hex 80000001; asc ;; *** (2) TRANSACTION: TRANSACTION 53A8, ACTIVE 8 sec starting index read mysql tables in use 1, locked 1 3 lock struct(s), heap size 376, 2 row lock(s) MySQL thread id 96, OS thread handle 0x70001062e000, query id 1425 localhost root Updating update t1 set level = 1 where name = "A" *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 89 page no 4 n bits 72 index `uk_name` of table `lock_demo2`.`t1` trx id 53A8 lock mode S Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 1; hex 41; asc A;; 1: len 4; hex 80000001; asc ;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 89 page no 4 n bits 72 index `uk_name` of table `lock_demo2`.`t1` trx id 53A8 lock_mode X locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 1; hex 41; asc A;; 1: len 4; hex 80000001; asc ;; *** WE ROLL BACK TRANSACTION (2)
來詳細看一下這個死鎖日志
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 89 page no 4 n bits 72 index uk_name of table lock_demo2.t1 trx id 53A7 lock_mode X locks rec but not gap waiting
事務 1 想獲取 uk_name 唯一索引上的 X 鎖 (非 gap 鎖的記錄鎖)
*** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 89 page no 4 n bits 72 index uk_name of table lock_demo2.t1 trx id 53A8 lock mode S
事務 2 持有uk_name 唯一索引上的 S 鎖(共享鎖)
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 89 page no 4 n bits 72 index uk_name of table lock_demo2.t1 trx id 53A8 lock_mode X locks rec but not gap waiting
事務 2 想獲得 uk_name 唯一索引上的 X 鎖(非 gap 鎖的記錄鎖)
跟之前理論上推斷的結論是一致的
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持創新互聯。
分享名稱:通過唯一索引S鎖與X鎖來了解MySQL死鎖套路
本文來源:http://vcdvsql.cn/article2/iijjoc.html
成都網站建設公司_創新互聯,為您提供網站收錄、、ChatGPT、網站制作、云服務器、網站導航
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯