死鎖案例三

1、環境說明

MySQL5.6.33,隔離級別是RR。表結構及數據:

create table t2 (
  id int primary key auto_increment ,
  c1 int ,
  c2 int ,
  key (c1)
) engine=innodb ;
insert into t2 values(24,3,4),(25,3,4),(26,3,4),(30,5,8);

2、測試用例


session1session2
begin;begin;
select *from t2 where id=30 for update;

update t2 set c2=8 where c1=5;
delete from t2 where id=30;

deadlock

3、死鎖日誌

LATEST DETECTED DEADLOCK
------------------------
2018-07-14 06:45:32 a3522b90
*** (1) TRANSACTION:
TRANSACTION 8976, ACTIVE 104 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320, 2 row lock(s)
MySQL thread id 2, OS thread handle 0xa34f1b90, query id 28 localhost root Searching rows for update
update t2 set c2=8 where c1=5
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 19 page no 3 n bits 72 index `PRIMARY` of table `yzs`.`t2` trx id 8976 lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 32
 0: len 4; hex 8000001e; asc     ;;
 1: len 6; hex 00000000230f; asc     # ;;
 2: len 7; hex 0d000001410943; asc     A C;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000008; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 8975, ACTIVE 251 sec updating or deleting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
MySQL thread id 1, OS thread handle 0xa3522b90, query id 29 localhost root updating
delete from t2 where id=30
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 19 page no 3 n bits 72 index `PRIMARY` of table `yzs`.`t2` trx id 8975 lock_mode X locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 32
 0: len 4; hex 8000001e; asc     ;;
 1: len 6; hex 00000000230f; asc     # ;;
 2: len 7; hex 0d000001410943; asc     A C;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000008; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 19 page no 4 n bits 72 index `c1` of table `yzs`.`t2` trx id 8975 lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 4; hex 8000001e; asc     ;;

*** WE ROLL BACK TRANSACTION (1)

4、分析死鎖日誌

TRANSACTION 8975:

    執行完delete from t2 where id=30後,擁有的鎖是聚集索引記錄(30,5,8)的X類型的記錄鎖lock_mode X locks rec but not gap,申請等待的鎖是二級索引記錄(5,30)的X類型的記錄鎖lock_mode X locks rec but not gap waiting。

TRANSACTION 8976:

    執行完update t2 set c2=8 where c1=5語句時,顯示申請等待的鎖是聚集索引記錄(30,5,8)的X類型的記錄鎖lock_mode X locks rec but not gap waiting。

只從死鎖日誌上看不出造成死鎖的原因。未提交的事務中,有已執行過但未提交的SQL語句鎖造成擁有的鎖沒有顯示出來。

5、加鎖原理

update加鎖原理見之前博客:

    https://blog.csdn.net/yanzongshuai/article/details/80872095

    https://blog.csdn.net/yanzongshuai/article/details/80870957

    https://blog.csdn.net/yanzongshuai/article/details/80870949

delete加鎖原理見之前博客:

    https://blog.csdn.net/yanzongshuai/article/details/79243727

    https://blog.csdn.net/yanzongshuai/article/details/79222041


6、解析

    session1執行完select *from t2 where id=30 for update;後,搜索到主鍵30,即對(30,5,8)加上X類型的記錄鎖

    session2執行完update t2 set c2=8 where c1=5;後,在search階段先搜索二級索引,搜索到(5,30),對此記錄加X類型的next-key鎖 lock_mode X;然後搜索聚集索引記錄30,需要對聚集索引記錄(30,5,8)加X類型記錄鎖,因爲和session1互斥,所以鎖等待。

    session1再次執行delete from t2 where id=30;,對記錄鎖聚集索引記錄(30,5,8)申請X類型的記錄鎖,因爲事務前面已申請過,所以不再申請;再對二級索引記錄(5,30)加X類型的記錄鎖,和session2互斥。

    這樣彼此發生鎖等待,造成死鎖。


7、解決方法

楊奇龍兄建議可以將session2的update t2 set c2=8 where c1=5改成按主鍵更新 update tx set c2=x where id=30。這樣加鎖順序都是先聚集再二級索引,避免主鍵和二級索引加鎖順序交叉造成死鎖。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章