是否可以创建具有只读访问权限的死锁?

Posted

技术标签:

【中文标题】是否可以创建具有只读访问权限的死锁?【英文标题】:Is it possible to create a deadlock with read-only access? 【发布时间】:2010-10-25 05:33:37 【问题描述】:

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

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

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

有人可以解释一下吗?

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

我选择 adOpenForwardOnly 还是 adOpenStatic 没有区别 光标位置是客户端还是服务器没有区别。

【问题讨论】:

我希望您现在已经了解到 READ 肯定会死锁,许多答案都指出了这是如何发生的。现在您需要做功课并提供其余信息,即。谁在和死锁图进行死锁。 不幸的是,我只能在生产系统上重现该问题,所以我必须慢慢来,不要急于求成。此外,我只能通过 ***/VNC/远程桌面/自定义文件传输工具(不要问)的奇怪组合访问服务器,因此即使是单次检查或复制新的可执行文件也需要很长时间。 【参考方案1】:

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

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

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

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

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

【讨论】:

据我所知,跟踪标志是全局的,即它们影响每个连接。由于该问题仅发生在生产服务器上,因此我必须等待一段时间才能做到这一点而不会冒任何问题。 是的,它们是全局的,但是额外的日志记录对性能的影响很小。 IMO 最好在生产服务器上启用此标志,这样您就可以确保在发生死锁时捕获信息(死锁很难重现),但是我不是 DBA...【参考方案2】:

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

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

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

注意死锁可以有更多的参与者,而不仅仅是 2 个。有时,一整串相互交织的活动会导致死锁,但原理是一样的。

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

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

【讨论】:

【参考方案3】:

这里描述的几个案例:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/05/03/when-index-covering-prevents-deadlocks.aspx

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

adOpenForwardOnly 的行为是否相同?

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

【讨论】:

...您检查过所有索引/统计信息是否都是最新的?【参考方案6】:

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

【讨论】:

是的,这将是我在许多其他应用程序中观察到的正常行为:阻塞,可能还有超时。【参考方案7】:

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

wikipedia 有一个关于死锁条件的很好的解释

【讨论】:

“当然你可以创建一个只读访问的死锁,因为读取不会等待”——这对我来说没有意义。【参考方案8】:

不会是这样吧?

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

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

【讨论】:

根据我的经验,这只会阻止我的应用程序并最终产生超时 我自己没有使用过,但显然 SQL 服务器上的跟踪标志 1204 将帮助您确定发生死锁的位置。见msdn.microsoft.com/en-us/library/ms178104.aspx

以上是关于是否可以创建具有只读访问权限的死锁?的主要内容,如果未能解决你的问题,请参考以下文章

我如何配置一个用户具有只读访问权限,而另一用户具有对Hangfire仪表板的完全访问权限?

多个线程可以具有只读访问权限的互斥模式

如何授予 Redshift 中所有模式的使用权限?

如何在 Linux 上设置具有 HTTP 访问权限的 Git 服务器

如何检查我的ios8自定义键盘扩展是否具有开放访问权限?

PostgreSQL(丢失数据的复制或复制)-远程主PostgreSQL的只读权限