SQL   Server   2005中解决死锁问题数据库操作的死锁是不可避免的,本文并不打算讨论死锁如何产生,重点在于解决死锁,通过SQL   Server   2005,   现在似乎有了一种新的解决办法。  将下面的SQL语句放在两个不同的连接里面,并且在5秒内同时执行,将会发生死锁。  
use   Northwind
begin   tran
  insert   into   Orders(CustomerId)   values(@#ALFKI@#)
  waitfor   delay   @#00:00:05@#
  select   *   from   Orders   where   CustomerId   =   @#ALFKI@#
commit
print   @#end   tran@#      
SQL   Server对付死锁的办法是牺牲掉其中的一个,抛出异常,并且回滚事务。在SQL   Server   2000,语句一旦发生异常,T-SQL将不会继续运行,上面被牺牲的连接中,   print   @#end   tran@#语句将不会被运行,所以我们很难在SQL   Server   2000的T-SQL中对死锁进行进一步的处理。  现在不同了,SQL   Server   2005可以在T-SQL中对异常进行捕获,这样就给我们提供了一条处理死锁的途径:  下面利用的try   ...   catch来解决死锁。  
SET   XACT_ABORT   ON
declare   @r   int
set   @r   =   1
while   @r   <=   3
begin
  begin   tran
  
  begin   try   
    insert   into   Orders(CustomerId)   values(@#ALFKI@#)
    waitfor   delay   @#00:00:05@#
    select   *   from   Orders   where   CustomerId   =   @#ALFKI@#
    
    commit
    break
  end   try
    
  begin   catch
    rollback
    waitfor   delay   @#00:00:03@#
    set   @r   =   @r   +   1
    continue
  end   catch
end      
解决方法当然就是重试,但捕获错误是前提。rollback后面的waitfor不解决方法当然就是重试,但捕获错误是前提。rollback后面的waitfor不可少,发生冲突后需要等待一段时间,@retry数目可以调整以应付不同的要求。  但是现在又面临一个新的问题:   错误被掩盖了,一但问题发生并且超过3次,异常却不会被抛出。SQL   Server   2005   有一个RaiseError语句,可以抛出异常,但却不能直接抛出原来的异常,所以需要重新定义发生的错误,现在,解决方案变成了这样:  
declare   @r   int
set   @r   =   1
while   @r   <=   3
begin
  begin   tran
  
  begin   try   
    insert   into   Orders(CustomerId)   values(@#ALFKI@#)
    waitfor   delay   @#00:00:05@#
    select   *   from   Orders   where   CustomerId   =   @#ALFKI@#
    
    commit
    break
  end   try
    
  begin   catch
    rollback
    waitfor   delay   @#00:00:03@#
    set   @r   =   @r   +   1
    continue
  end   catch
end
if   ERROR_NUMBER()   <>   0
begin
  declare   @ErrorMessage   nvarchar(4000);
  declare   @ErrorSeverity   int;
  declare   @ErrorState   int;
  select
    @ErrorMessage   =   ERROR_MESSAGE(),
    @ErrorSeverity   =   ERROR_SEVERITY(),
    @ErrorState   =   ERROR_STATE();
  raiserror   (@ErrorMessage,
          @ErrorSeverity,
          @ErrorState
          );
end      
我希望将来SQL   Server   2005能够直接抛出原有异常,比如提供一个无参数的RaiseError。  因此方案有点臃肿,但将死锁问题封装到T-SQL中有助于明确职责,提高高层系统的清晰度。现在,对于DataAccess的代码,或许再也不需要考虑死锁问题了