SQLServer事务与另一个进程已被死锁

Posted on 2008-07-15 23:57 沙龙 阅读(6492) 评论(0)  编辑 收藏 引用 所属分类: 数据库

MS的说明:
错误 1205
严重级别 13
消息正文
事务(进程 ID %1!)与另一个进程已被死锁在资源 {%2!} 上,且该事务已被选作死锁牺牲品。请重新运行该事务。
解释
当 Microsoft? SQL Server? 遇到死锁时发生该错误。当两个(或多个)进程试图访问某个资源,而该资源上有另一个进程控制的锁时,发生死锁。因为每个进程都有对另一个资源的请求,所以各进程都不能完成。当检测到死锁时,SQL Server 将处理时间最少的命令回滚,并向客户端应用程序返回错误信息 1205。该错误不是严重错误,且不会导致批处理终止。
对策
在某些情况下,死锁条件将导致 DB-Library 函数(如 dbsqlexec、dbsqlok、dbresults 或 dbnextrow)返回 FAIL。程序应该始终检查从每个 DB-Library 函数返回的代码。如果这些 DB-Library 函数之一返回 FAIL,则程序应取消批处理并停止运行。在某些情况下,继续执行批处理中的后续函数是有可能的。但是,因为发生了死锁情况并且回滚了引起死锁的函数,所以批处理中的后续函数将可能因更严重的错误(如"没有找到对象")而失败。
在其它情况下,死锁条件不会导致 DB-Library 函数返回 FAIL。在这些情况下,程序必须在消息处理程序中检查是否有错误信息 1205,并使用 dbsetuserdata 函数将此信息告知应用程序。然后程序必须在每个 DB-Library 调用之后检查是否有死锁指示符,如果检测到死锁则应取消批处理。
尽管在收到 1205 死锁消息后取消批处理可能似乎没有必要,但因为服务器并不总是终止死锁情况下的批处理,所以这确实必要。如果未取消批处理,则任何时候试图提交新的批处理时均将导致 DB-Library 错误 10038"结果挂起"。
还可以使用 SET DEADLOCK_PRIORITY 语句(LOW 或 NORMAL)。SET DEADLOCK_PRIORITY 控制在发生死锁情况时会话的反应方式。如果设置为 LOW,则进程将成为死锁情况下的首选牺牲品。如果设置为 NORMAL,则会话将使用默认的死锁处理方法。
如果死锁情况持续,则使用跟踪标记 1204 收集更多信息通常很有用。跟踪标记 1204 打印死锁链和牺牲品,如以下示例输出所示:
*** Deadlock Detected ***
==> Process 7 chosen as deadlock victim
== Deadlock Detected at: 1998-09-10 16:39:29.17
== Session participant information:
SPID: 7 ECID: 0 Statement Type: UPDATE
Input Buf: update t1 set c1 = c1  where  c1 = 2
SPID: 8 ECID: 0 Statement Type: UPDATE
Input Buf: update t1 set c1 = c1  where  c1 = 1

== Deadlock Lock participant information:
== Lock: KEY: 2:117575457:1 (010001000000)
Database: tempdb
Table: t1
Index: i1
 - Held by: SPID 7 ECID 0 Mode "S"
 - Requested by: SPID 8 ECID 0 Mode "X"
== Lock: KEY: 2:117575457:1 (020002000000)
Database: tempdb
Table: t1
Index: i1
 - Held by: SPID 8 ECID 0 Mode "S"
 - Requested by: SPID 7 ECID 0 Mode "X"
此死锁信息可以解释如下:
第一部分显示死锁牺牲品、死锁时间以及死锁中涉及的会话。对于每个会话,显示当前的 SPID、语句类型和输入缓冲区的一部分。
第二部分显示有关死锁中涉及的锁的详细信息。从上面的输出,注意死锁涉及表 t1(索引 i1)上的键锁。死锁输出显示哪些进程拥有死锁中涉及的锁,哪些会话在等待锁被授权以及相关联的锁模式。
根据默认,生成最小日志量的进程将选作死锁牺牲品,并自动回滚。若要影响所回滚的会话,请为会话设置 DEADLOCK_PRIORITY。
出现这个问题首先要考虑数据库设计的问题,检查会不会由于循环锁引起死锁的问题,即关系互相依赖;第二就要检查程序的问题,作为数据库sa我认为应该从这三方面来检查问题。
1、执行:

dbcc traceon (1204, 3605, -1)
go
dbcc tracestatus(-1)
go

目的是把锁信息写到日志上(../log/Errlog)文件上,以检查分析锁的产生;
注: 有关DBCC的介绍我会另外写一篇文章介绍
2、设置lock_timeout变量的时间
select @@lock_timeout (查询当前设置)
set lock_timeout 1800 (设置当前会话的当前锁超时设置,单位为毫秒)
这个应该和程序开发人员商量,嵌入在程序里。 (未做过,待测试:))
3、设置DEADLOCK_PRIORITY变量
控制在发生死锁情况时会话的反应方式。具体请查看联机文档。

只有注册用户登录后才能发表评论。

posts - 19, comments - 5, trackbacks - 0, articles - 5

Copyright © 沙龙