最近因為業務的需求寫了一段時間存儲過程,發現之前寫的存儲過程存在一些不嚴謹的地方,特别是TRY...CATCH中嵌套事務的寫法;雖然之前寫的并沒有錯,但是還是埋藏着很大的隐患在裡面。希望這篇文章能給大家一些參考;文章内容有點長還望耐心閱讀。


THROW是在2012版本中引入的,在有些場景當中,應用程式端不做一些合法性的驗證,這些驗證會被放在資料庫端來驗證。當資料庫端驗證輸入的資訊不合法時需要主動抛出異常來中斷代碼的執行。
THROW既可以接收錯誤資訊抛錯提示,同時也可以手動抛出錯誤到CATCH中。文法如下:


注意:
1.THROW代碼前必須要用分号,因為THROW會中斷代碼的執行,是以如果将THROW放在CATCH中時必須放在ROLLBACK TRAN之後,否則不會復原事務導緻對象一直處于送出狀态被鎖。
2.THROW放CATCH中可以達到RAISERROR一樣的效果,同時還簡便了代碼。
3. THROW能傳回正确的錯誤代碼行号,而RAISERROR沒辦法
自定義錯誤号


注意:自定義錯誤号必須大于50000


調用存儲過程:


調用存儲過程
可以發現使用RAISERROR抛錯出來的行号和消息号都是錯誤的,50000這個消息号其實是不存在的,它是保留的一個統一的消息号。
可以通過查詢sys.message查詢對應的消息号
手動抛錯也是這篇文章主要要講的一個知識點,在有一些業務場景當中有一些驗證操作需要在資料庫中進行,甚至必須在更新之後進行但是又是正常的送出操作,在這種情況下就需要手動進行驗證是否需要執行下面的代碼。,見過很多程式員寫存儲過程喜歡在每一個判斷的地方加上RETURN操作,目的是為了不執行後面的代碼,同時又在RETURN前加上ROLLBACK操作。這雖然是一個辦法,但是在事務中運用RETURN是一個很危險的操作,弄不好會導緻事務一直處于打開操作導緻表一直被鎖住,在生成環境是很危險的操作。
建議使用THROW來手動進行抛錯,THROW抛錯會相當于觸發一個11-19級别的錯誤,這樣會跳到CATCH中做ROLLBACK操作。
注意:THROW前必須以分号開頭,如果THROW前有代碼以分号結尾也可以。


5.存儲過程調用存儲過程


存儲過程調用存儲過程事務的三種處理方法:
1.内部存儲過程不要包含事務,因為内部ROLLBACK會直接復原到外部的BEGIN TRAN導緻外部的ROLLBACK沒有對應的COMMIT;
2.還有一種方法是在調用内部存儲過程之前使用儲存點“SAVE TRAN TRAN1”,同時内部存儲過程的ROLLBACK TRAN必須指定事務儲存點,例如“ROLLBACK TRAN TRAN1”,這樣内部存儲過程復原就隻會復原到保持點.
3.在外部存儲過程的CATCH塊的ROLLBACK前加上IF @@TRANCOUNT > 0判斷條件
事務嵌套事務的了解


對于事務嵌套事務,事務2的ROLLBACK操作會直接復原到事務1的BEGIN TRAN,會導緻事務1的ROLLBACK沒有對應的BEGIN TRAN。處理方法可以在調用事務2之前定義一個事務儲存點或者在事務1的ROLLBACK前加上IF @@TRANCOUNT > 0判斷條件是否存在事務需要復原。
并不是所有的錯誤都能被CATCH所接收。對于嚴重級别為0-10(資訊性消息)和20-25(緻命的消息)是不能被CATCH所接收的,這時如果在事務中遇到了這類的報錯那麼通用會導緻事務處理打開狀态,這時就需要開啟XACT_ABORT。當開啟XACT_ABORT後隻要代碼中存在報錯就會執行復原操作,而不管錯誤的級别。例如:


由于臨時表#BB不存在,導緻插入報錯,但是嚴重級别又小于11導緻CATCH接收不到錯誤,這時檢視發現事務處于打開狀态,而且表AA也被鎖住。
加上事務前加上 SET XACT_ABORT ON


再次執行
沒有處于打開的事務而且事務也執行了復原操作。
1.建議2012以後版本所有的接收抛錯改成使用THROW,不要使用THROW抛錯又使用RAISERROR來介紹錯誤,在事務嵌套事務的寫法中如果内部事務使用RAISERROR來接收THROW傳回的報錯不會執行後面的ROLLBACK。
2.建議在ROLLBACK前統一加上IF @@TRANCOUNT > 0判斷條件,這樣可以避免因為内部的ROLLBACK復原或者RETURN操作導緻ROLLBACK沒有對應的COMMIT。
3.建議不要在事務内使用RETURN傳回代碼錯誤位置,RETURN會跳出事務導緻提示ROLLBACK沒有對應的COMMIT,嚴重的會導緻事務一直處于打開不送出,THROW也可以指定錯誤位置。
4.CATCH隻是用來處理TRY報錯之後的邏輯,不要認為代碼執行到了CATCH的ROLLBACK就會結束處理,除非是在ROLLBACK後加入了RETURN或者THROW之類的中斷代碼執行的指令,否則代碼還将繼續執行ROLLBACK之後的代碼甚至END CATCH之後的代碼(如果存在)。
本文轉自pursuer.chen(陳敏華)部落格園部落格,原文連結:http://www.cnblogs.com/chenmh/p/7856777.html,如需轉載請自行聯系原作者