數(shù)據(jù)庫操作的死鎖是不可避免的,本文并不打算討論死鎖如何產(chǎn)生,重點在于解決死鎖,通過sql server 2005, 現(xiàn)在似乎有了一種新的解決辦法。
將下面的sql語句放在兩個不同的連接里面,并且在5秒內(nèi)同時執(zhí)行,將會發(fā)生死鎖。
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對付死鎖的辦法是犧牲掉其中的一個,拋出異常,并且回滾事務(wù)。在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 
解決方法當(dāng)然就是重試,但捕獲錯誤是前提。rollback后面的waitfor不可少,發(fā)生沖突后需要等待一段時間,@retry數(shù)目可以調(diào)整以應(yīng)付不同的要求。
但是現(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中有助于明確職責(zé),提高高層系統(tǒng)的清晰度。現(xiàn)在,對于dataaccess的代碼,或許再也不需要考慮死鎖問題了。
新聞熱點
疑難解答
圖片精選