如何使用事务内的INSERT和UPDATE语句来防止此死锁

时间:2018-05-10 11:22:44

标签: mysql transactions innodb

我有两张表table_atable_b。在我的应用程序中,我有一个业务方法,它执行以下操作:

// it is one transaction

INSERT INTO table_b (join_col) VALUES (some_value);

UPDATE table_a a 
JOIN table_b b ON a.join_col = b.join_col AND a.column_a = b.column_b
SET a.column_c = a.column_c + 1;

我正在使用InnoDB引擎,问题是,当我并行或几乎并行运行我的方法时,我经常收到此错误消息:

  

试图锁定时发现死锁;尝试重新启动交易

似乎第一个事务开始更新table_a并锁定table_b,而第二个并行事务无法插入table_b,因为它已被锁定。

如果我评论我的UPDATE州政府,它就会开始工作。两个事务都插入到table_b中没有问题。那么,我该如何解决呢?如果重要,我正在使用MySQL 5.7。

2 个答案:

答案 0 :(得分:1)

看起来你正在锁定表b,然后表a。可能锁是一个索引锁。

试试这个,总是首先抓住桌子上适当的锁。

BEGIN TRANSACTION;
  SELECT COUNT(join_col) INTO @counter 
    FROM table_a a
   WHERE a.join_col = some_value
     FOR UPDATE;
  INSERT INTO table_b (join_col) VALUES (some_value);
  UPDATE table_a a 
    JOIN table_b b ON a.join_col = b.join_col 
                  AND a.column_a = b.column_b
     SET a.column_c = a.column_c + 1;
COMMIT;

INTO @counter内容会阻止第一个SELECT将结果集返回给您的程序。

如果不起作用,请尝试使用LOCK TABLES。这是一个很大的锤子,但很有效。

LOCK TABLES table_a, table_b WRITE;
 your queries
UNLOCK TABLES;

答案 1 :(得分:0)

这看起来很奇怪。

  1. 将一堆值插入B。
  2. 使用所有这些值来更新另一个表。
  3. 好吧,如果你在另一个帖子中玩相同的 B,你期望什么?您不希望B中的事物列表发生变化。

    考虑使用local normalizedString = str:gsub("[%z\1-\127\194-\244][\128-\191]*", tableAccents) 代替B ??