[英]How to simulate a deadlock on a row in mysql?
To simulate a lock
in mysql I can grab the row with the following:要模拟 mysql 中的
lock
,我可以使用以下命令获取该行:
BEGIN;
SELECT * FROM table WHERE id=1 FOR UPDATE;
Now, if I try and update that row (from another connection) it will raise the following error after innodb_lock_wait_timeout
seconds (default: 50):现在,如果我尝试更新该行(从另一个连接),它将在
innodb_lock_wait_timeout
秒后引发以下错误(默认值:50):
(1205, 'Lock wait timeout exceeded; try restarting transaction')
(1205, '超过锁定等待超时;尝试重新启动事务')
How would I simulate a deadlock then, so I get an error that looks like:那么我将如何模拟死锁,所以我得到一个看起来像这样的错误:
Deadlock found when trying to get lock;
尝试获取锁时发现死锁; try restarting transaction”
尝试重启交易”
When I try and query or update the row?当我尝试查询或更新行时?
Update : even when trying to simulate the mysql deadlock example
, I get Lock wait timeout exceeded; try restarting transaction
更新:即使尝试模拟
the mysql deadlock example
,我也得到Lock wait timeout exceeded; try restarting transaction
Lock wait timeout exceeded; try restarting transaction
rather than a deadlock
message. Lock wait timeout exceeded; try restarting transaction
而不是deadlock
消息。
Is Deadlock Detection enabled?是否启用了死锁检测?
You can read more here: https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-detection.html您可以在这里阅读更多信息: https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlock-detection.ZFC35FDC70D5FC69D2698Z83A822C7A5E3
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.
可以使用 innodb_deadlock_detect 配置选项禁用死锁检测。
Lock another table in another transaction and then try to access other transactions table.在另一个事务中锁定另一个表,然后尝试访问其他事务表。 For example:
例如:
In transaction A
lock table 1
在事务
A
锁表1
In transaction B
lock table 2
在事务
B
锁表2
In transaction A
to update table 2
在事务
A
中更新表2
In transaction B
to update table 1
.在事务
B
中更新表1
。
Also, you can increase your timeout to 5 minutes so that while you are creating your deadlock it doesn't timeout.此外,您可以将超时时间增加到 5 分钟,以便在创建死锁时不会超时。
UPDATE: An example更新:一个例子
In session A
:在 session
A
:
START TRANSACTION;
UPDATE tbl1 SET b=1 WHERE id=1;
in session B
:在 session
B
中:
START TRANSACTION;
UPDATE tbl2 SET b=1 WHERE id=1;
Then然后
In session A
:在 session
A
:
UPDATE tbl2 SET b=1 WHERE id=1;
in session B
:在 session
B
中:
UPDATE tbl1 SET b=1 WHERE id=1;
First of all, refering to your last edit, the example in the manual should work.首先,参考您上次的编辑, 手册中的示例应该可以工作。 If it doesn't, there is either a fundamental problem, or you are missing some detail, so I would start there and make sure that you get it working.
如果没有,则要么存在根本问题,要么您遗漏了一些细节,因此我将从那里开始并确保您可以正常工作。
The deadlock example has 3 steps, and I suspect you may have missed the last one:死锁示例有 3 个步骤,我怀疑您可能错过了最后一个步骤:
T1: select
T1:
select
T2: delete
. T2:
delete
。 T2 has to wait for T1 now. T2 现在必须等待 T1。 Waiting means, that MySQL currently still sees a possible way that both T1 and T2 can finish successfully, For example.
等待意味着,MySQL 目前仍然看到了一种可能的方式,即 T1 和 T2 都可以成功完成,例如。 T1 can just commit now, Noone knows.
T1 现在可以提交,没人知道。 so T2 waits for what happens, If you wait too long in this step.
所以T2等待发生什么,如果你在这一步等待太久。 you will get a timeout (which is what I suspect happened).
你会得到一个超时(这是我怀疑发生的)。
T1: delete
. T1:
delete
。 This will result in a deadlock in T2.这将导致 T2 中的死锁。 You need this last step to create a non-resolvable conflict.
您需要最后一步来创建不可解决的冲突。
You should try that example first, and carefully, as the devil is in the details.您应该首先仔细尝试该示例,因为魔鬼在细节中。 Leading to a detail in your own example:
在您自己的示例中引出一个细节:
You are using SELECT... FOR UPDATE
.您正在使用
SELECT... FOR UPDATE
。 FOR UPDATE
is actually a way to reduce the number of deadlocks (which is the opposite of what you want), at the price of locking more restrictively. FOR UPDATE
实际上是一种减少死锁数量的方法(这与您想要的相反),代价是锁定更严格。 Eg you have more situation where MySQL waits just to be safe, instead of going on and hoping it will work out eventually (or not, hence deadlock).例如,您有更多的情况 MySQL 只是为了安全而等待,而不是继续并希望它最终会解决(或不会,因此陷入僵局)。 Note that the example in the manual uses
LOCK IN SHARE MODE
for that reason.请注意,出于这个原因,手册中的示例使用
LOCK IN SHARE MODE
。
So to modify and expand your own example to get a deadlock, you can do所以要修改和扩展你自己的例子来获得死锁,你可以这样做
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 completeness (and to exclude a potential misunderstanding): the row has to exists, if your table is eg empty, you won't get a deadlock.为了完整性(并排除潜在的误解):该行必须存在,如果您的表为空,则不会出现死锁。
If you use FOR UPDATE
instead, you don't get a deadlock, but T2 keeps waiting until you commit/rollback T1.如果您改用
FOR UPDATE
,则不会出现死锁,但 T2 会一直等到您提交/回滚 T1。 It has to do with the way locking works, but you can maybe get an idea of that if you add a select
to T2:它与锁定的工作方式有关,但如果您将
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
If you replace both LOCK IN SHARE MODE
with FOR UPDATE
, T2 will wait at/before the select
, until T1 commits, without a deadlock.如果将
LOCK IN SHARE MODE
都替换为FOR UPDATE
,则 T2 将在select
处/之前等待,直到 T1 提交,而不会出现死锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.