mysql - SELECT FOR UPDATE 和 INSERT ON DUPLICATE KEY UPDATE 导致 MYSQL 中同一行插入时出现死锁

标签 mysql transactions innodb deadlock

我正在同时执行多个事务,并且当通过 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,因为我在结果更新之前根据先前的结果维护计数。由于插入而产生死锁。

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

最佳答案

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

接受它。重新启动被破坏的事务。

关于mysql - SELECT FOR UPDATE 和 INSERT ON DUPLICATE KEY UPDATE 导致 MYSQL 中同一行插入时出现死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50745897/

相关文章:

php - 当 mysql_num_rows 说有数据时,mysql_fetch_array 返回 false,为什么?

PHP 从数组计算日期范围

database - Google 的 App Engine 是否适合基于事务的系统

Java Spring @Transactional 方法没有按预期回滚

python - while 循环中的变量赋值

mysql - MySQL INSERT .. SELECT 语句的 auto_increment 字段值顺序是什么

java - 在 hibernate 中如何以编程方式设置事务的隔离级别,或者如何创建两个具有不同隔离级别的事务

mysql - 批量更新大型 InnoDB 表中未索引的列

mysql - INSERT 的 MySQL 事务是否锁定外键引用表?

mysql - 使用唯一的多列索引表的最佳方法?