在这种情况下我怎么能死锁呢?

时间:2009-11-11 22:51:31

标签: sql mysql database deadlock

在我的客户端应用程序中,我有一个这样的方法(实际上它更复杂,但我已离开主要部分):

public void btnUpdate_Click(...)
{
  ...
  dataAdapter.Update(...);
  ...
  dataAdapter.Fill(...); // here I got exception one time
}

我在日志中发现的异常说“尝试锁定时发现死锁;尝试重启事务”。我只是在时间遇到这个例外,所以没有重复 据我所知,DataAdapter.Fill()方法只执行select查询。我没有进行显式交易,我启用了自动提交 那么如何才能在一个简单的选择查询上获得死锁?这个查询不是更大事务的一部分? 据我所知,要获得死锁,两个事务应该等待彼此。如果单个选择不在交易中,那怎么可能呢?也许这是MySql中的一个错误?

提前谢谢。

4 个答案:

答案 0 :(得分:1)

你是对的,需要两个事务才能造成死锁。也就是说,单个事务中的任何语句或语句都不会与 同一事务 中的其他语句发生死锁。

但它只需要一个事务就能注意到死锁的报告。你怎么知道你看到报告死锁的事务是在数据库中执行的唯一事务?这个数据库中没有其他活动吗?

另外。你的陈述“我没有做出明确的交易”,而“ ......这不是更大的事务的一部分”意味着你不明白每一个SQL执行的语句始终处于隐式事务中,即使您没有显式启动它也是如此。

大多数数据库都有专门用于跟踪,报告和/或记录死锁实例的报告机制,以便进行诊断。在SQL服务器中有一个跟踪标志,它会导致日志条目详细说明每个发生的死锁,包括所涉及的两个事务中的每一个的详细信息,例如正在执行的sql语句,数据库中的哪些对象被锁定,以及为什么无法获得锁定。我猜我的MySQL有类似的诊断工具。找出它是什么并将其打开,以便下次发生这种情况时,您可以查看并确切了解发生了什么。

答案 1 :(得分:0)

您可以针对其他语句(如UPDATE)对一个简单的SELECT进行死锁。在我的博客上,我有一个例子来解释两个调优好的语句之间的死锁:Read/Write deadlock。虽然该示例是SQL Server特定的,但原则是通用的。我没有足够的MySQL知识来声称这是必然的,特别是考虑到MySQL可以部署的各种引擎,但是简单的SELECT可能是死锁的受害者。

答案 2 :(得分:0)

我没有研究MySQL事务的工作原理,但这是基于MSSQL事务的工作方式:

如果您没有使用交易,则每个查询都有一个交易。否则,每当中间更新失败时,你就会变得一团糟。

死锁的原因可能是锁定升级。数据库尝试为每个查询尽可能少地锁定,因此它只通过锁定受影响的单行开始。当页面中的大多数行被查询锁定时,它可能会决定将锁升级为锁定整个页面会更好,这可能会产生锁定某些行而不会受查询影响的副作用。

如果select查询和update查询试图升级同一个表上的锁,它们可能会导致死锁,尽管只涉及一个表。

答案 3 :(得分:0)

我同意在这个特定的问题中,这不太可能成为问题,但这是对限制其范围的其他答案的补充,为后人记录,以防有人发现它有用。

MySQL在极少数情况下会有单个语句定期死锁自己。这似乎特别发生在批量插入上,并且问题几乎肯定是与操作相关的不同线程之间的死锁。我希望批量更新有同样的问题。在过去遇到此类问题时,我通常只会在单个语句中减少插入(或更新)的行数。

,在这种情况下尝试获取锁定时,通常会遇到死锁。

我和我的同事正在讨论MS SQL Server中的类似问题(因此这不是MySQL独有的!)并且他指出解决方案是告诉服务器不要并行化插入或更新。这里的问题是与自旋锁相关的死锁,而不是RDBMS中的逻辑锁死锁。