天天看點

一個線上死鎖問題分析

死鎖日志如下:

transaction 48aa4bb9, active 0 sec inserting

mysql tables in use 1, locked 1

lock wait 6 lock struct(s), heap size 1248, 4 row lock(s), undo log entries 2

mysql thread id 1409173, os thread handle 0x5659f940, query id 1084083936 10.246.138.197 bop_libra update

insert into deadlock_test

(deadlock_config_id, block_id, type, gmt_create, gmt_modified)

values

(31643, 92354, 1, now(), now());

*** (1) waiting for this lock to be granted:

record locks space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48aa4bb9 lock_mode x insert intention waiting

*** (2) transaction:

transaction 48aa4bbf, active 0 sec inserting, thread declared inside innodb 500

5 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 2

mysql thread id 1393832, os thread handle 0x7699f940, query id 1084083946 10.246.138.197 bop_libra update

(31643, 92353, 1, now(), now());

*** (2) holds the lock(s):

record locks space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48aa4bbf lock_mode x

*** (2) waiting for this lock to be granted:

record locks space id 17 page no 161 n bits 584 index `idx_block_id` of table `deadlock`.`test_deadlock` trx id 48aa4bbf lock_mode x insert intention waiting

*** we roll back transaction (2)

表上有聚集索引和二級索引,死鎖發生在二級索引idx_block_id上。

首先,從死鎖資訊:

可以确定,這個x鎖不是由于insert産生的。

insert可能産生的鎖包括檢查dup key時的s鎖,隐式鎖轉換為顯式鎖(not gap,要在二級索引上産生lock_mode為x的lock_ordinary類型的鎖(包括記錄及記錄前面的gap),據我所知一般是根據二級索引掃描進行記錄更新導緻的。

從5 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 2

有2個undo entires,而單純的insert一條記錄隻有一個undo entry,是以可以推斷除了insert,必然還有别的操作.)

基于以上,事務除了insert,可能還存在delete/update,并且這些操作是走的二級索引來查找更新記錄。

一個簡單但不完全相同的重制步驟:

drop table t1;

create table `t1` (

  `a` int(11) not null auto_increment,

  `b` int(11) default null,

  `c` int(11) default null,

  primary key (`a`),

  key `b` (`b`)

) engine=innodb ;

insert into t1(a, b,c) values(1,2,3),(5,4,6),(8, 7,9),(12,12,19),(15,15,11);

session1:

begin;

delete from t1 where b = 12;

//二級索引上lock_mode x、lock_mode x locks gap before rec以及主鍵上的lock_mode x locks rec but not gap

二級索引:heap_no=5, type_mode=3  (12上的lock_ordinary類型鎖,包括記錄和記錄前的gap)

聚集索引:heap_no=5,type_mode=1027

二級索引:heap_no=6,type_mode=547(15上的gap鎖)

session2:

delete from t1 where b = 7;

二級索引:heap_no=4,type_mode=3       (7上的lock_ordinary類型鎖,包括記錄和記錄前的gap)

聚集索引:heap_no=4,type_mode=1027

二級索引:heap_no=5,type_mode=547    (記錄12上的gap鎖)

insert into t1 values (null, 6,10);

//新插入記錄聚集索引無沖突插入成功,二級索引等待插入意向鎖(lock_mode x locks gap before rec insert intention waiting)

二級索引,heap_no=4, type_mode=2819 (請求記錄7上面的插入意向鎖lock_x | lock_gap | lock_insert_intention, 需要等待session2

insert into t1 values (null, 7,10);

二級索引:heap_no=5,  type_mode=2819  (請求記錄12上的插入意向鎖lock_x | lock_gap | lock_insert_intention,需要等待session1)

互相等待,導緻發生死鎖

從列印的死鎖資訊來看,基本和線上發生的死鎖現象是一緻的。

繼續閱讀