要在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
消息。
答案 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个步骤,我怀疑您可能错过了最后一个步骤:
T1:select
T2:delete
。 T2现在必须等待T1。等待的意思是,MySQL当前仍然认为T1和T2都可以成功完成!例如,T1可以立即提交。没有人知道,所以T2等待发生的事情。如果您在此步骤中等待的时间太长,则会超时(这是我怀疑发生的情况)。
T1:delete
。这将导致T2死锁。您需要最后一步来创建不可解决的冲突。
您应该首先仔细尝试该示例,因为细节中有魔鬼。在您自己的示例中给出详细信息:
您正在使用SELECT ... FOR UPDATE
。 FOR 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提交为止,而没有死锁。