如何在 mysql 中的一行上模拟死锁?
How to simulate a deadlock on a row in mysql?
要在 mysql 中模拟 lock
我可以使用以下内容获取该行:
BEGIN;
SELECT * FROM table WHERE id=1 FOR UPDATE;
现在,如果我尝试更新该行(从另一个连接),它将在 innodb_lock_wait_timeout
秒(默认值:50)后引发以下错误:
(1205, 'Lock wait timeout exceeded; try restarting transaction')
那么我将如何模拟死锁,所以我得到一个如下所示的错误:
Deadlock found when trying to get lock; try restarting transaction”
当我尝试查询或更新行时?
更新:即使在尝试模拟 the mysql deadlock example
时,我也会收到 Lock wait timeout exceeded; try restarting transaction
而不是 deadlock
消息。
是否启用了死锁检测?
您可以在这里阅读更多内容:https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-detection.html
A mechanism that automatically detects when a deadlock occurs, and automatically rolls back one of the transactions involved (the victim). Deadlock detection can be disabled using the innodb_deadlock_detect configuration option.
在另一个事务中锁定另一个 table,然后尝试访问其他事务 table。
例如:
在交易中A
锁定table1
在交易中B
锁定table2
在事务A
中更新table2
在事务B
中更新table1
。
此外,您可以将超时增加到 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;
首先,参考您上次的编辑,example in the manual 应该有效。如果没有,则可能存在根本性问题,或者您遗漏了一些细节,所以我会从这里开始,确保您能正常使用它。
死锁示例有 3 个步骤,我怀疑您可能错过了最后一个步骤:
T1: select
T2:delete
。 T2 现在必须等待 T1。等待意味着,MySQL 目前仍然可以看到 T1 和 T2 都可以成功完成的可能方式!例如,T1 现在就可以提交。没有人知道,所以 T2 等待发生的事情。如果您在此步骤中等待的时间过长,您将超时(我怀疑发生了这种情况)。
T1:delete
。这将导致 T2 中的死锁。您需要这最后一步来创建 non-resolvable 冲突。
你应该先尝试那个例子,而且要小心,因为细节决定成败。在你自己的例子中引出一个细节:
您正在使用 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
为了完整性(并排除潜在的误解):该行必须存在,如果您的 table 例如空,你不会陷入僵局。
如果您改用 FOR UPDATE
,则不会出现死锁,但 T2 会一直等到您 commit/rollback T1。它与锁定的工作方式有关,但如果您将 select
添加到 T2:
,您也许可以了解这一点
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 将等待 at/before 和 select
,直到 T1 提交,不会出现死锁。
要在 mysql 中模拟 lock
我可以使用以下内容获取该行:
BEGIN;
SELECT * FROM table WHERE id=1 FOR UPDATE;
现在,如果我尝试更新该行(从另一个连接),它将在 innodb_lock_wait_timeout
秒(默认值:50)后引发以下错误:
(1205, 'Lock wait timeout exceeded; try restarting transaction')
那么我将如何模拟死锁,所以我得到一个如下所示的错误:
Deadlock found when trying to get lock; try restarting transaction”
当我尝试查询或更新行时?
更新:即使在尝试模拟 the mysql deadlock example
时,我也会收到 Lock wait timeout exceeded; try restarting transaction
而不是 deadlock
消息。
是否启用了死锁检测?
您可以在这里阅读更多内容:https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-detection.html
A mechanism that automatically detects when a deadlock occurs, and automatically rolls back one of the transactions involved (the victim). Deadlock detection can be disabled using the innodb_deadlock_detect configuration option.
在另一个事务中锁定另一个 table,然后尝试访问其他事务 table。 例如:
在交易中A
锁定table1
在交易中B
锁定table2
在事务A
中更新table2
在事务B
中更新table1
。
此外,您可以将超时增加到 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;
首先,参考您上次的编辑,example in the manual 应该有效。如果没有,则可能存在根本性问题,或者您遗漏了一些细节,所以我会从这里开始,确保您能正常使用它。
死锁示例有 3 个步骤,我怀疑您可能错过了最后一个步骤:
T1:
select
T2:
delete
。 T2 现在必须等待 T1。等待意味着,MySQL 目前仍然可以看到 T1 和 T2 都可以成功完成的可能方式!例如,T1 现在就可以提交。没有人知道,所以 T2 等待发生的事情。如果您在此步骤中等待的时间过长,您将超时(我怀疑发生了这种情况)。T1:
delete
。这将导致 T2 中的死锁。您需要这最后一步来创建 non-resolvable 冲突。
你应该先尝试那个例子,而且要小心,因为细节决定成败。在你自己的例子中引出一个细节:
您正在使用 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
为了完整性(并排除潜在的误解):该行必须存在,如果您的 table 例如空,你不会陷入僵局。
如果您改用 FOR UPDATE
,则不会出现死锁,但 T2 会一直等到您 commit/rollback T1。它与锁定的工作方式有关,但如果您将 select
添加到 T2:
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 将等待 at/before 和 select
,直到 T1 提交,不会出现死锁。