我有一个包含以下架构的表:
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)