MySQL InnoDB引擎在同一更新查询中两次采用相同的独占锁

时间:2016-12-07 11:09:57

标签: mysql innodb deadlock

我有一个包含以下架构的表:

CREATE TABLE `my_table` (
  `id` int(11) NOT NULL,
  `type` enum('type1','type2','type3') NOT NULL,
  `date` datetime NOT NULL,
  `latest_id` int(11) DEFAULT NULL,
  `value` varchar(255) NOT NULL,
  `lastModified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `data_source` varchar(16) DEFAULT NULL,
  `active` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `type_idx` (`type`),
  KEY `value_idx` (`value`(12)),
  KEY `latest_id` (`latest_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

正在运行此更新查询(没有更大的事务,只有这个查询):(编辑 - 更新以查询匹配的死锁日志)

UPDATE
    my_table a
    INNER JOIN my_table b
        ON a.id = b.latest_id
SET a.active = 1, b.active= 1
WHERE a.latest_id IS NULL
    AND a.type = 'type1'
    AND a.data_source = 'source1'
    AND (a.iactive = 0 OR b.active = 0)
    ORDER BY a.id, b.id;

我已经遇到上述更新查询导致死锁,取出一行上的X锁,另一个事务出现并等待同一行的X锁,然后上面的查询尝试取出完全相同的X锁第二次。

为什么尝试在此行上取出一个X锁定?

这个查询导致这种行为的原因是什么?我之前在查询有子选择但没有连接的情况下看过这个。有更好的等价物吗?

死锁日志的一个示例:

161205  0:00:00
*** (1) TRANSACTION:
TRANSACTION 3F3B262A3, ACTIVE 10 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 9226725, OS thread handle 0x7f3f72cde700, query id 4161514375 164.54.80.104 XXX Updating
-- user=XXX progname=XXX host=XXX pid=XXX ldsn=XXX
-- DBI::db=HASH(XXX)
UPDATE my_table SET date = '2016-12-01 00:00:00', lastModified = '2016-12-05 00:19:12' WHERE id = '13178'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1082331 page no 95862 n bits 288 index `PRIMARY` of table `XXX`.`my_table` trx id 3F3B262A3 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 3F3B251E1, ACTIVE 119 sec fetching rows, thread declared inside InnoDB 398
mysql tables in use 2, locked 2
61982 lock struct(s), heap size 6961592, 11189728 row lock(s)
MySQL thread id 9227900, OS thread handle 0x7f4007a4b700, query id 4161470712 172.20.7.110 XXX Sending data
-- user=XXX progname=XXX host=XXX pid=XXX ldsn=XXX

    UPDATE 
        my_table a 
        INNER JOIN my_table b 
            ON a.id = b.latest_id 
    SET a.active = 1, b.active = 1 
    WHERE a.latest_id IS NULL 
        AND a.type = 'type1' 
        AND a.data_source = 'source1' 
        AND (a.active = 0 OR b.active = 0)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1082331 page no 95862 n bits 288 index `PRIMARY` of table `XXX`.`my_table` trx id 3F3B251E1 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1082331 page no 95862 n bits 288 index `PRIMARY` of table `XXX`.`my_table` trx id 3F3B251E1 lock_mode X waiting
*** WE ROLL BACK TRANSACTION (1)

0 个答案:

没有答案