【问题标题】:SELECT FOR UPDATE and INSERT ON DUPLICATE KEY UPDATE causes deadlock in MYSQL on same row insertionSELECT FOR UPDATE 和 INSERT ON DUPLICATE KEY UPDATE 导致 MYSQL 在同一行插入时出现死锁
【发布时间】:2018-06-07 16:15:02
【问题描述】:

我同时执行多个事务,当通过 SELECT FOR UPDATE 查询检查同一行并使用 INSERT ON DUPLICATE KEY UPDATE 插入或更新时,会发生这种情况。但这会导致死锁。

这是表架构

CREATE TABLE `t` (
  `a` varchar(40) NOT NULL,
  `b` date NOT NULL,
  `c` enum('a','b') COLLATE utf8_bin NOT NULL,
  `d` char(12) NOT NULL,
  `e` TINYINT(1) UNSIGNED NOT NULL,
  PRIMARY KEY (`a, `b`, `c`, `d` )
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

以下是事务操作。

在交易 1 中:

Start Transaction;

SELECT  *
FROM t
WHERE
    a= '123'
        AND `b` = '2017-01-01'
        AND c= 'a'
        AND d= '1'
FOR UPDATE;

INSERT INTO t
(`a`, b, `c` , d, e)
VALUES ('123', '2017-01-01', 'a' , '1'  , '2')
ON DUPLICATE KEY UPDATE `e` = '2';

Commit;

在交易 2 中:

Start Transaction;

SELECT  *
FROM t
WHERE
    a= '123'
        AND `b` = '2017-01-01'
        AND c= 'a'
        AND d= '1'
FOR UPDATE;

INSERT INTO t
(`a`, b, `c` , d, e)
VALUES ('123', '2017-01-01', 'a' , '1'  , '2')
ON DUPLICATE KEY UPDATE `e` = '2';

Commit;

当两个事务都运行 select for update 并且其中一个事务尝试插入行时,就会发生死锁。

注意:我需要 SELECT FOR UPDATE,因为我会在结果更新之前根据之前的结果进行计数。插入导致死锁。

问题:如何避免死锁问题?

【问题讨论】:

  • MySQL 不会锁定尚不存在的特定行(巧合的是,它被称为“for update”,而不是“for insert”,尽管它实际上不是(完整的)解释。)你可能能够重新组织您的查询,例如插入作为第一步,或者例如使用第二个表插入行只是为了能够锁定它。

标签: mysql transactions innodb deadlock


【解决方案1】:

InnoDB 的事务处理并不十分精确。出于性能考虑,一些非死锁被视为死锁,因为努力发现其他情况是不值得的成本和稀有性。

忍受它。重新启动被 zapped 的事务。

【讨论】:

    猜你喜欢
    • 2022-11-03
    • 2011-08-09
    • 2011-01-29
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多