0

在我的开发环境中,我试图重新创建我们在 MSSQL 2005 中面临的生产问题。这个问题有两个部分:

问题

1) 发生死锁,MSSQL 选择一个连接(“连接 X”)作为“受害者”。2) 所有后续使用“连接 X”的尝试都失败了(我们使用连接池)。MSSQL 说“服务器无法恢复事务”

在这两者中,#2 如果更严重的话:由于“连接 X”每次“循环”尝试重新使用“连接 x”都会失败 - 并且神秘的“随机”错误出现在用户面前。我们必须重新启动服务器。

我为什么写作

然而,在这一点上,我希望重新创建问题 #1。我可以轻松地制造死锁。

但这是我的问题:虽然在生产中,MSSQL 选择一个连接 (SPID) 作为“死锁受害者”,但在我的测试环境中,死锁只是挂起......然后挂起又挂起。永远?我不确定,但我把它挂了一夜,早上它仍然挂着。

那么问题来了:当死锁发生时,如何让 sql server “选择死锁受害者”?

迄今为止的尝试

我尝试通过 jdbc url 设置“lock_timeout”参数(“lockTimeout=5000”),但是我得到的消息与生产中不同(在测试中,“超过锁定请求超时期限。”而不是在生产中“事务(处理ID 59)与另一个进程在锁资源上死锁,并被选为死锁牺牲品。”)

关于问题 #2 的一些细节

我研究了这个“无法恢复交易”的问题,发现了一些事情:

  • 错误的异常处理可能会导致此问题。例如:java 代码不会关闭 Statement/PreparedStatement,并且驱动程序的“Connection”实现卡在了错误/陈旧/旧的“事务 ID”中
  • jdbc 驱动程序升级可能会使问题消失。

但是,现在,我只想重新创建死锁并使 sql server “选择死锁受害者”。

提前致谢!

附录 A. 技术环境

发展:

  • sql server 2005 SP3 (9.00.4035.00)
  • 驱动:sqljdbc.jar 1.0版
  • Jboss 3.2.6
  • jdbc url: jdbc:sqlserver://<>;

生产:

  • sql server 2005 SP2 (9.00.3042.00)
  • 驱动:sqljdbc.jar 1.0版
  • Jboss 3.2.6
  • jdbc url: jdbc:sqlserver://<>;

附录 B. 强制死锁的步骤

  • 获取连接 A
  • 获取连接 B
  • 使用连接 A 运行 sql1
  • 使用连接 B 运行 sql2
  • 使用连接 B 运行 sql1
  • 使用连接 A 运行 sql2

where sql1: update member set name = name + 'x' WHERE member_id = 71

sql2: 更新成员集名称 = 名称 + 'x' WHERE member_id = 72

4

4 回答 4

0

您可以使用指定会话的死锁优先级 f

SET DEADLOCK_PRIORITY LOW | MEDIUM | HIGH

有关详细信息,请参阅此MSDN链接。

您还可以使用以下命令查看未结交易

DBCC OPENTRAN (db_name)

此命令可以帮助您确定导致死锁的原因。有关详细信息,请参阅MSDN

于 2009-08-27T15:29:41.797 回答
0

正在运行什么查询?究竟是什么导致了僵局?

你说你有两个连接A和B。A运行sql1然后sql2,而B运行sql2然后sql1。那么,正在完成的工作(查询)是什么?更重要的是,交易在哪里?您使用的是什么隔离级别?什么打开/关闭交易?(是的,这会导致对您的驱动程序使用的异常处理提出质疑——如果他们没有检测并正确处理返回的“它不起作用”消息,那么您绝对需要将它们取出并射击它们——子弹或青霉素,你的电话。)

了解死锁背后的显式细节将允许您重新创建它。我首先尝试在您的应用程序“下方”重新创建它——也就是说,在 SSMS 中打开两个窗口,并在必要时手动重新创建应用程序的操作。一旦你能做到这一点,退后一步,在你的应用程序中复制它——当然,所有这些都在你的开发服务器上!

(一个想法——你的开发数据库是你的生产数据库的副本吗?如果开发数据库比生产数据库小几个数量级,你的查询可能是相同的,但 SQL 在“幕后”所做的事情将大不相同。)

最后一个想法,SQL 将自动检测和处理死锁(我真的不认为你可以禁用它),如果你的运行在一夜之间,那么我认为你没有死锁,而只是一个传统的锁定/阻塞问题。

[现在发布这个 - 去查找一些东西,稍后再回来查看。]
[稍后]

有趣——SQL Server 2005 精简版不检测死锁,它只检测超时。你没有在 Dev 中使用它,是吗?

我看不到“关闭”或以其他方式控制死锁超时期限的方法。就在上周,我遇到了死锁并搞砸了,然后一些任意测试表明死锁在 5 秒内(对于我们的开发服务器)被检测到并解决。看起来你的开发机器上没有死锁,只是阻塞。但是要意识到这些东西对于“扶手椅 DBA”来说很难分析,当这个问题发生时,你真的需要坐下来认真分析系统内部发生的事情。

于 2009-08-27T15:47:01.497 回答
0

这里给出了为什么JDBc连接进入错误状态的解释:服务器未能恢复事务...为什么?. 您应该先升级到JDBC SQL 驱动程序 v2.0。该链接还包含有关如何修复应用程序处理以避免这种情况的建议,最重要的是避免将 JDBC 事务 API 与本机 Transact-SQL 事务混合使用。

至于死锁重现:您没有在测试中重新创建死锁。您刚刚阻止等待事务提交。死锁是另一回事,SQL Server选择受害者,您不必设置死锁优先级、锁定超时或任何其他内容。死锁优先级是一个完全不同的主题,用于在某些场景中选择受害者,例如高优先级与低优先级夜间批处理。

如果您想消除死锁,任何死锁调查都应该从了解死锁开始。Profiler 中的Dedlock Graph 事件类是完美的起点。通过死锁图信息,您可以查看发生死锁的资源以及涉及的语句。大多数情况下,解决方案是修复应用程序中的更新顺序(始终遵循相同的顺序)或修复访问路径(即添加索引)。

更新

  • UPDATE .. WHERE key IN (SELECT ...)通常是死锁,因为操作不是原子的。多个线程可以返回相同的IN 列表,因为 SELECT 部分不锁定任何内容。这只是一个猜测,要正确验证您必须查看死锁信息。

  • 要验证您手工制作的死锁测试,您应该验证阻塞 SPID 是否形成了循环。看SELECT session_id, blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id <> 0。如果结果包含一个循环(例如,A 被 B 阻止,B 被 A 阻止)并且服务器不会触发死锁,那就是一个错误。但是,你会发现阻塞列表不会形成循环,会是A被B阻塞,B被C阻塞,C不在列表中,这意味着你在repro测试中做错了。

于 2009-08-27T16:41:27.423 回答
0

[这是对答案的回应。UI 不允许对答案进行更长的“评论”]

正在运行什么查询?究竟是什么导致了僵局?

在我的测试环境中,我运行了非常简单的查询:

sql1:更新主体 SET 名称 = 名称 + '.' 其中 principal_id = 71

sql2:更新主体 SET 名称 = 名称 + '.' 其中 principal_id = 72

然后以交叉/交叉顺序执行它们,即没有任何提交。

连接A

 sql1

   connectionB

      sql2

      sql1

 sql2

在我看来,这似乎是僵局的一个基本示例。然而,如果这是一个“单纯的锁”,而不是一个死锁,请不要让我怀疑这个概念。

在生产中,我们的“有问题的查询”(“prodbad”)看起来像这样:

更新后 SET lock_flag = ? WHERE thread_id IN (SELECT thread_id FROM POST WHERE post_id = ?)

注意几点:

1)这个“产品问题查询”确实有效。AFAIK这一次陷入僵局

2)我怀疑问题在于页面锁定,即由于在事务中的其他地方读取而导致的悲观锁定

3)我不知道这个事务在这个查询之前执行了什么sql。

4)这个查询是“我可以在一个 sql 语句中做到这一点”处理的一个例子,虽然这对程序员来说似乎很聪明,但最终导致的 IO 比运行两个查询要多得多:

queryM:SELECT thread_id FROM POST WHERE post_id = ?

queryN: UPDATE post SET lock_flag = ? WHERE thread_id = <>

*>(一个想法——你的开发数据库是你的生产数据库的副本吗?

如果开发数据库比生产数据库小几个数量级,那么您的查询可能是相同的,但 > SQL 在“幕后”所做的将大不相同。)*

在这种情况下,prod 和 dev db 不同。“产品服务器”有大量数据。“Dev db”的数据很少。查询非常不同。我想做的就是重新造成死锁。

*> 服务器无法恢复交易...为什么?你应该升级到 JDB

C SQL 驱动程序 v2.0 先于其他任何东西。*

谢谢。我们计划进行此更改。切换驱动程序会带来一点风险,所以我们需要运行一些测试..

回顾一下:

我有一个“好主意”来强制一个简单的死锁,看看我的连接是否“重击/软管/中断/等等”。然而,僵局的表现与生产中不同。

于 2009-08-28T17:00:26.333 回答