10

我有一个 VB6 应用程序通过 ADO 访问 MSSQL2000 服务器上的单个表。我正在使用只读访问(adOpenStatic、adLockReadOnly) 网络中还有其他应用程序会对表进行更改。

出于某种原因,我收到关于我的应用程序被选为死锁受害者的错误。

我真的很困惑:当我只是从一个表中读取时,为什么会出现死锁?我希望超时,因为其他应用程序的编写,但不是死锁......

有人可以对此有所了解吗?

更新:2009-06-15我仍然对这个问题的解决方案感兴趣。所以我提供了更多信息:

  • 如果我选择 adOpenForwardOnly 或 adOpenStatic 没有区别
  • 如果光标位置是客户端或服务器,则没有区别。
4

8 回答 8

16

由于存在非聚集索引,单个 SELECT 语句可能会因单个 UPDATE 或 DELETE 语句而死锁,请考虑以下情况:

阅读器(您的应用程序)首先在非聚集索引上获取共享锁以执行查找,然后尝试在包含数据的页面上获取共享锁以返回数据本身。

writer(其他应用程序)首先在包含数据的数据库页面上获得排他锁,然后尝试在索引上获得排他锁以更新索引。

您可以在 Microsoft 知识库文章 Q169960 ( http://support.microsoft.com/kb/q169960/ )中找到有关此(和其他)类型死锁的更多信息

此外,您可能想在 Google 上查看如何获取死锁跟踪信息(跟踪标志 1222) - 这将准确报告发生死锁时哪些 SQL 语句与哪些对象发生冲突。这是一篇相当不错的文章 - http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx

于 2009-05-27T12:57:20.593 回答
3

我认为这里已经提供的答案有很多可能性。由于您只使用共享锁,因此死锁不可能是由于锁升级,而必须只是获取与在另一个进程中获取的锁不兼容的锁,并以不同的顺序获取这些锁......

您的共享锁与另一个使用独占锁的进程不兼容。场景可能会像这样运行......

  1. 您对资源 A 进行共享锁定
  2. 其他进程对资源 B 进行排他锁
  3. 其他进程试图获取资源 A 的独占锁,并阻塞等待您释放 A 上的共享锁。
  4. 您尝试在资源 B 上获取共享锁,并且会阻塞等待其他进程释放其在 B 上的独占锁,除非您现在处于死锁情况,这由服务器识别并选择要杀死的进程.

NB 死锁可以有更多的玩家,而不仅仅是 2 个。有时会有一整条相互交织的活动链导致死锁,但原理是一样的。

通常,如果多个应用程序访问同一个数据库,则有一个 DBA 通过存储过程管理所有访问,因此他可以确保资源始终以相同的顺序锁定。如果您不处于这种情况,并且其他应用程序使用临时 SQL 语句,则您必须检查它们的代码,以确定它们是否可能与您的应用程序发生冲突,就像我描述的那样。这听起来不好玩。

一个实用的解决方案可能是在您的事务作为死锁受害者被杀死时捕获错误,然后简单地重试事务几次。根据其他应用程序生成的活动量,您可能会通过这种方式获得可接受的结果。

于 2009-06-16T11:18:23.160 回答
0

读取仍然会导致锁定,以便数据库确保在非自动读取过程中不会完成写入。换句话说,读锁确保您获得所选择的任何数据的准确一致的快照。

于 2009-05-11T08:08:57.233 回答
0

你有同样的行为adOpenForwardOnly吗?

您可能想要检查您的 SQL Server 统计信息是否是最新的。或者您可以让您的 DBA 重建所有索引。许多锁定问题是由于过时的统计信息/索引造成的。

于 2009-05-11T08:11:32.173 回答
-1

这取决于两个应用程序的行为。您的应用程序肯定可以等待对方释放资源。

于 2009-05-11T08:07:08.047 回答
-1

死锁是指两个或多个进程相互等待释放资源,或两个以上进程在循环链中等待资源的情况。当然,您可以创建具有只读访问权限的死锁,因为读取不会等待。

关于维基百科的死锁条件有一个很好的解释

于 2009-05-11T08:09:49.680 回答
-2

不会是这样吗?

其他应用:写入表(获取表上的写锁)

您的应用程序:从表中读取(获取表上的读锁,由于写锁而不能)。

于 2009-05-11T08:03:36.040 回答