插入导致InnoDB死锁。这怎么发生的?

时间:2014-06-20 12:29:54

标签: mysql insert innodb deadlock

我的问题是:为什么事务1持有主锁,为什么事务2需要主锁?我在mysql手册中找不到关于此锁的任何信息。

有关此死锁的信息:

交易1:

1988266681 Query        BEGIN
1988266681 Query        INSERT IGNORE INTO `tab1`
                            (`sn`, `is_fetch`, `is_done`, `add_time`)
                            VALUES ('4287', 0, 0, 1403186277)
1988266681 Query        COMMIT

交易2:

1988212988 Query        BEGIN
1988212988 Query        SELECT sn FROM tab1 WHERE is_fetch = 0
                            LIMIT 200 FOR UPDATE
1988212988 Query        UPDATE `tab1` SET `is_fetch` = 1
                            WHERE sn in ('4287', '4387', '4487', '4587', '4687',
                            '4787', '4887', '4987')
1988212988 Query        COMMIT

架构信息:

CREATE TABLE `tab1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sn` varchar(20) NOT NULL,
`is_fetch` tinyint(1) NOT NULL DEFAULT '0' ,
`is_done` tinyint(1) NOT NULL DEFAULT '0' ,
`add_time` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sn` (`sn`),
KEY `is_fetch` (`is_fetch`),
KEY `is_done` (`is_done`)
) ENGINE=InnoDB AUTO_INCREMENT=4387619 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

死锁信息:

------------------------
LATEST DETECTED DEADLOCK
------------------------
140617 23:25:36
*** (1) TRANSACTION:
TRANSACTION 36E4099DA, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 1937033606, OS thread handle 0x2ae3b0040700, query id 18031163883 192.168.1.65 db1 update
INSERT IGNORE INTO `tab1` (`sn`, `is_fetch`, `is_done`, `add_time`) VALUES ('1887', 0, 0, 1403018736)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 625 page no 5 n bits 1616 index `is_fetch` of table `db1`.`tab1` trx id 36E4099DA lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 1476 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 1; hex 81; asc  ;;
1: len 4; hex 80410669; asc  A i;;

*** (2) TRANSACTION:
TRANSACTION 36E4099D7, ACTIVE 0 sec fetching rows, thread declared inside InnoDB 458
mysql tables in use 1, locked 1
6 lock struct(s), heap size 3112, 51 row lock(s), undo log entries 7
MySQL thread id 1937007092, OS thread handle 0x2ae8b5a26700, query id 18031163880 192.168.1.130 db1 Updating
UPDATE `tab1` SET `is_fetch` = 1 WHERE sn in ('1187', '1287', '1387', '1487', '1587', '1687', '1787')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 625 page no 5 n bits 1616 index `is_fetch` of table `db1`.`tab1` trx id 36E4099D7 lock_mode X locks gap before rec
Record lock, heap no 1476 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 1; hex 81; asc  ;;
1: len 4; hex 80410669; asc  A i;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 625 page no 3 n bits 440 index `PRIMARY` of table `db1`.`tab1` trx id 36E4099D7 lock_mode X waiting
Record lock, heap no 168 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 80411598; asc  A  ;;
1: len 6; hex 00036e4099da; asc   n@  ;;
2: len 7; hex e80000c0060110; asc        ;;
3: len 14; hex 3134303631373338343331383837; asc 1887;;
4: len 1; hex 80; asc  ;;
5: len 1; hex 80; asc  ;;
6: len 4; hex d3a05df0; asc   ] ;;

2 个答案:

答案 0 :(得分:2)

问:这是怎么发生的?

事务2获得了对'is_fetch`索引中记录的独占锁定,并尝试获取表中PRIMARY键中记录的锁定。

事务1获得对表的PRIMARY键中记录的独占锁定,并尝试获取is_fetch索引中记录的锁定。

InnoDB会自动检测到两个事务都无法进行,因为每个事务都持有另一个事务所需的资源。 InnoDB终止其中一个事务,以便其他事务可以继续。

请注意,INSERT语句可以为唯一索引中的记录获取“间隙”锁定。导致死锁的不仅仅是INSERT,而是同时运行的事务组合。

InnoDB记录锁定在MySQL参考手册中有记录:

http://dev.mysql.com/doc/refman/5.5/en/innodb-record-level-locks.html

答案 1 :(得分:-1)

SELECT ... FOR UPDATE获取已扫描行的锁定。您可以在这里更多地了解:http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.htmlhttp://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html