在我的开发环境中,我试图重新创建我们在 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