在SQL Server中,我常常會看到有些前輩這樣寫:
if(@@error<>0) ROLLBACK TRANSACTION T else COMMIT TRANSACTION T
一開始,我看見別人這么寫,我就想當然的以為它只是個計數器,每當檢測到一處錯誤時,@@error的值+1,不過就因為這個理所當然,所以杯具了...
實際上,它並不是一個計數器,它是一個動態的值,動態的標識最后一條SQL命令執行的結果,如果成功則為0,不成功則標識錯誤碼。所以,像上面這種寫法是不妥的,舉個例子,如下:
SET NOCOUNT ON; SET XACT_ABORT ON; --執行 Transact-SQL 語句產生運行時錯誤,則整個事務將終止並回滾 BEGIN TRANSACTION T UPDATE Test SET a='已更新' WHERE a='未更新' RAISERROR ('不好意思,你沒有權限!',16,1)
SELECT GETDATE() if(@@error<>0) ROLLBACK TRANSACTION T else COMMIT TRANSACTION T
分析:
按我以前的理解來說,【 RAISERROR ('不好意思,你沒有權限!',16,1) 】這里拋出了一個錯誤,整個事務應該回滾才對,可是,它卻沒有回滾!!那么原因出在哪呢?原來,問題出在"SELECT GETDATE()"這句上面!因為執行RAISERROR語句時,@@error的值不為0(好像是5000),而當執行到下一句"SELECT GETDATE()"時,@@error的值又變為0了!所以,后面的if語句自然沒有捕捉到任何錯誤...
對策:
既然找到了原因,那解決辦法自然也少不了。用Try...CATCH語法就可以了,語句如下:
SET NOCOUNT ON; SET XACT_ABORT ON; --執行 Transact-SQL 語句產生運行時錯誤,則整個事務將終止並回滾 BEGIN TRY BEGIN TRANSACTION T UPDATE Test SET a='已更新' WHERE a='未更新' RAISERROR ('不好意思,你沒有權限!',16,1) SELECT GETDATE() COMMIT TRANSACTION T END TRY BEGIN CATCH DECLARE @msg nvarchar(2000)=ERROR_MESSAGE() --將捕捉到的錯誤信息存在變量@msg中 RAISERROR (@msg,16,1) --此處才能拋出(好像是這樣子....) ROLLBACK TRANSACTION T --出錯回滾事務 END CATCH