如何在mysql中模拟死锁?

时间:2020-08-21 04:10:18

标签: mysql innodb

要在mysql中模拟lock,我可以使用以下命令获取行:

BEGIN;
SELECT * FROM table WHERE id=1 FOR UPDATE;

现在,如果我尝试(从另一个连接)更新该行,它将在innodb_lock_wait_timeout秒(默认值:50)之后引发以下错误:

(1205,“超出了锁定等待超时;尝试重新启动事务”)

然后我将如何模拟死锁,所以出现如下错误:

尝试获取锁时发现死锁;尝试重新开始交易”

当我尝试查询或更新行时?


更新:即使尝试模拟the mysql deadlock example,我也会收到Lock wait timeout exceeded; try restarting transaction而不是deadlock消息。

3 个答案:

答案 0 :(得分:2)

是否启用了死锁检测?

您可以在此处了解更多信息:https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-detection.html

一种机制,可以自动检测何时发生死锁,并自动回滚所涉及的事务之一(受害方)。可以使用innodb_deadlock_detect配置选项禁用死锁检测。

答案 1 :(得分:2)

锁定另一个事务中的另一个表,然后尝试访问其他事务表。 例如:

在事务A中的锁定表1

在事务B中的锁定表2

在事务A中更新表2

在事务B中更新表1

此外,您可以将超时时间增加到5分钟,以便在创建死锁时不会超时。

更新: 一个例子

在会话A中:

START TRANSACTION;
UPDATE tbl1 SET b=1 WHERE id=1;

在会话B中:

START TRANSACTION;
UPDATE tbl2 SET b=1 WHERE id=1;

然后

在会话A中:

UPDATE tbl2 SET b=1 WHERE id=1;

在会话B中:

UPDATE tbl1 SET b=1 WHERE id=1;

答案 2 :(得分:1)

首先,参考您的上一次编辑,example in the manual应该可以使用。如果没有,则可能是根本问题,或者您缺少一些细节,所以我将从那里开始,并确保您可以使用它。

死锁示例包含3个步骤,我怀疑您可能错过了最后一个步骤:

  1. T1:select

  2. T2:delete。 T2现在必须等待T1。等待的意思是,MySQL当前仍然认为T1和T2都可以成功完成!例如,T1可以立即提交。没有人知道,所以T2等待发生的事情。如果您在此步骤中等待的时间太长,则会超时(这是我怀疑发生的情况)。

  3. T1:delete。这将导致T2死锁。您需要最后一步来创建不可解决的冲突。

您应该首先仔细尝试该示例,因为细节中有魔鬼。在您自己的示例中给出详细信息:

您正在使用SELECT ... FOR UPDATEFOR UPDATE实际上是一种减少死锁数量的方法(这与您想要的相反),但代价是更严格地限制了锁定。例如。您有更多的情况,MySQL等待只是为了安全起见,而不是继续运行并希望它最终会成功(否则就不会因此而死锁)。请注意,出于该原因,手册中的示例使用LOCK IN SHARE MODE

因此,您可以修改并扩展自己的示例以获取僵局

 T1: START TRANSACTION;
     SELECT * FROM table WHERE id=1 LOCK IN SHARE MODE;

 T2: START TRANSACTION;
     UPDATE table SET id=2 WHERE id=1 
      -- wait

 T1: UPDATE table SET id=2 WHERE id=1 
     -- deadlock in T2 

为了完整性(并排除潜在的误解):如果您的表例如是空的,您不会陷入僵局。

如果改用FOR UPDATE,则不会出现死锁,但是T2会一直等到提交/回滚T1为止。它与锁定的工作方式有关,但是如果您在T2中添加select,您可能会有所了解:

 T1: START TRANSACTION;
     SELECT * FROM table WHERE id=1 LOCK IN SHARE MODE;

 T2: START TRANSACTION;
     SELECT * FROM table WHERE id=1 LOCK IN SHARE MODE;
     -- fine in shared mode. Waits here if you use `for update`!

 T1: UPDATE table SET id=2 WHERE id=1 
     -- wait

 T2: UPDATE table SET id=2 WHERE id=1 
     -- deadlock 

如果将两个LOCK IN SHARE MODE都替换为FOR UPDATE,则T2将在select之前/之前等待,直到T1提交为止,而没有死锁。