在这种情况下如何获得死锁?
Posted
技术标签:
【中文标题】在这种情况下如何获得死锁?【英文标题】:How can I get dead lock in this situation? 【发布时间】:2009-11-11 22:51:30 【问题描述】:在我的客户端应用程序中,我有一个这样的方法(实际上它更复杂,但我已经离开了主要部分):
public void btnUpdate_Click(...)
...
dataAdapter.Update(...);
...
dataAdapter.Fill(...); // here I got exception one time
我在日志中发现的异常是“尝试获取锁定时发现死锁;尝试重新启动事务”。我只遇到过这个异常,所以没有重复。 据我了解, DataAdapter.Fill() 方法只执行选择查询。我没有进行显式事务,并且启用了自动提交。 那么如何才能在一个不属于更大事务的简单选择查询上获得死锁呢? 据我了解,要获得死锁,两个事务应该相互等待。使用不在事务中的单个选择怎么可能?也许这是mysql中的一个错误?
提前谢谢你。
【问题讨论】:
你找到解决这个问题的办法了吗? 【参考方案1】:你是对的,需要两个事务才能形成死锁。也就是说,单个事务中的任何语句或语句都不能与同一事务中的其他语句发生死锁。
但是只需要一个事务就可以注意到死锁的报告。你怎么知道你看到死锁报告的事务是数据库中唯一正在执行的事务?这个数据库中没有其他活动吗?
还有。您的陈述“我没有进行显式交易”和“...这不是更大交易的一部分”意味着您不了解每个 SQL执行的语句总是在一个隐式事务中,即使你没有显式地启动一个。
大多数数据库都有专门设计用于跟踪、报告和/或记录死锁实例以用于诊断目的的报告机制。在 SQL Server 中,有一个跟踪标志会导致一个日志条目,其中包含有关发生的每个死锁的详细信息,包括有关所涉及的两个事务中的每个事务的详细信息,例如正在执行的 sql 语句、数据库中的哪些对象被锁定,以及为什么无法获得锁。我猜 mySQL 有类似的诊断工具。找出它是什么并将其打开,以便下次发生这种情况时,您可以查看并确切了解发生了什么。
【讨论】:
'还有。您的陈述“我不进行显式事务”和“......这不是更大事务的一部分”意味着您不了解执行的每个 SQL 语句始终处于隐式事务中,即使您不这样做明确启动一个。” - 这是一个错误的结论。我清楚地知道。我在mysql论坛上询问是否有任何东西可以帮助跟踪/记录/理解mysql中的死锁。让我们看看。但你没有说我怎么能得到一个死锁。你能举一个简单的选择语句(在这个事务中没有其他内容)陷入死锁的例子吗?【参考方案2】:您可以针对 其他 语句(如 UPDATE)使简单的 SELECT 死锁。在我的博客上,我有一个示例解释了两个经过良好调整的语句之间的死锁:Read/Write deadlock。虽然该示例是特定于 SQL Server 的,但其原理是通用的。我没有足够的 MySQL 知识来声称这一定是这种情况,特别是考虑到 MySQL 可以部署的各种引擎,但是一个简单的 SELECT 也可能成为死锁的受害者。
【讨论】:
为了清楚起见,您可以将 Select 与 ANOTHER 事务中的其他语句死锁,而不是 SAME 事务中的其他语句...【参考方案3】:我还没有研究过 MySQL 事务的工作原理,但这是基于 MSSQL 事务的工作原理:
如果您不使用事务,则每个查询本身都有一个事务。否则每次更新在中间失败时你都会变得一团糟。
死锁的原因可能是锁升级。数据库尝试尽可能少地锁定每个查询,因此它首先锁定受影响的单行。当页面中的大多数行被查询锁定时,它可能会决定将锁定升级为锁定整个页面会更好,这可能会产生锁定一些不受查询影响的行的副作用。
如果select
查询和update
查询试图升级同一张表上的锁,即使只涉及一个表,它们也可能导致死锁。
【讨论】:
使用 MySQL 时,引擎之间的锁定差异很大。只有 InnoDB 有行级锁定,ISAM/MyISAM/Memory 都会锁定整个表以进行任何更新:dev.mysql.com/doc/refman/5.1/en/internal-locking.html 我刚刚问过 InnoDb 是否可以在 mysql 论坛上使用锁升级。让我们看看。【参考方案4】:我同意在这个特定问题中,这不太可能是问题,但这是对其他答案的补充,以限制其范围,记录下来以备后人发现它有用。
在极少数情况下,MySQL 可以让单个语句周期性地死锁。这似乎特别发生在批量插入上,并且问题几乎可以肯定是与操作相关的不同线程之间的死锁。我希望批量更新也有同样的问题。过去,当遇到此类问题时,我通常只是减少在单个语句中插入(或更新)的行数。在这种情况下,您通常不会在尝试获取锁时遇到死锁,而是会收到其他消息。
我的一位同事和我正在讨论 MS SQL Server 中的类似问题(所以这不是 MySQL 独有的!),他指出解决方案是告诉服务器不要并行化插入或更新。这里的问题是自旋锁相关的死锁,而不是 RDBMS 中的逻辑锁死锁。
【讨论】:
以上是关于在这种情况下如何获得死锁?的主要内容,如果未能解决你的问题,请参考以下文章