简体   繁体   English

如何在 mysql 中模拟一行死锁?

[英]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 个步骤,我怀疑您可能错过了最后一个步骤:

  1. T1: select T1: select

  2. 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).你会得到一个超时(这是我怀疑发生的)。

  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM