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,語句一旦發(fā)生異常,T-SQL將不會繼續(xù)運行,上面被犧牲的連接中, print @#end tran@#語句將不會被運行,所以我們很難在SQL Server 2000的T-SQL中對死鎖進行進一步的處理。
  
    現(xiàn)在不同了,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不可少,發(fā)生沖突后需要等待一段時間,@retry數(shù)目可以調整以應付不同的要求。
  
    但是現(xiàn)在又面臨一個新的問題: 錯誤被掩蓋了,一但問題發(fā)生并且超過3次,異常卻不會被拋出。SQL Server 2005 有一個RaiseError語句,可以拋出異常,但卻不能直接拋出原來的異常,所以需要重新定義發(fā)生的錯誤,現(xiàn)在,解決方案變成了這樣:  




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能夠直接拋出原有異常,比如提供一個無參數(shù)的RaiseError。
  
    因此方案有點臃腫,但將死鎖問題封裝到T-SQL中有助于明確職責,提高高層系統(tǒng)的清晰度。現(xiàn)在,對于DataAccess的代碼,或許再也不需要考慮死鎖問題了。

分享到

多易

相關推薦