碰到巢狀事務-筆記

zzm186發表於2014-09-23

相關SQL語句:

BEGIN TRAN

SAVE TRAN

COMMIT TRAN

ROLLBACK TRAN

巢狀事務示例:

BEGIN TRAN Tran1

BEGIN TRAN Tran2

COMMIT TRAN 可以單獨指定某個事務名,如Tran1,Tran2進行提交。其實也沒什麼效果,即使Tran2提交成功了,只要將外層事務Tran1回滾,Tran2儲存的資料照樣被回滾!
ROLLBACK TRAN 不能指定某個事務名進行回滾!只能ROLLBACK TRAN 或者 ROLLBACK TRAN Tran1,也就說只能回滾最外層的事務名。如果執行ROLLBACK TRAN Tran2,SQL會提示“無法回滾 Tran2。找不到該名稱的事務或儲存點”,出錯的原因就是因為Tran2不是最外層事務。總結一句話:ROLLBACK 要麼就所有事務都回滾,要麼就回滾時異常,一個事務都沒回滾!
ROLLBACK 可以回滾某個事務儲存點(SAVE TRAN TranSave1), 如ROLLBACK TRAN TranSave1,但是要明白的是,回滾事務儲存點並不會使事務數@TranCount減少,你巢狀了幾個事務,它還是有幾個事務數.
特別注意,如果在父儲存過程建立一個事務Tran1,然後在子儲存過程執行ROLLBACK TRAN後,子儲存過程會丟擲異常!事務只能在同一個儲存過程裡面建立、回滾和提交,不允許分離在不同的儲存過程裡面。
基於以上特點,我個人覺得巢狀事務的作用不大,SQL的內部處理其實最終就是處理一個最外層的事務點。SQL丟擲事務相關的異常,並不是程式碼有何問題,而是在提醒我們注意事務的控制。 我們只要採用TRY CATCH 方式捕獲相關異常就可以,我們只要確保設計的事務點能正常回滾或提交就OK了。


解決方法1:

  TRY CATCH 捕獲相關異常


解決方法2:

  如果外部已經有事務了,就不再建立內部事務。我想SQL的事務異常提醒就是為了告訴你,不能隨便一個地方放事務。

  IF @TRANCOUNT =0

        BEGIN TRAN

 


TRY CATCH 注意事項:

SQL語句不加try catch,即使出現異常,後續的SQL語句也會執行。但是一旦外部加了try catch,則會捕獲異常,導致後續的SQL語句沒有執行。
是否SQL的異常有分致命和普遍的,在沒加try catch的情況下,普通的可以繼續往下走,但是致命的就不往下走了。這個和C#程式語言有重大的不同,程式語言一旦出現異常,後續程式碼就不再執行!
在處理巢狀事務時,要特別注意,不論如何要確保事務被完整的關閉或被回滾!

回滾比較好控制。無論有多少級事務數,只要ROLLBACK 一次就可以。不過如果是ROLLBACK TRAN TRANNAME,TranName不是第一級的話,則會出現異常,等於沒有執行ROLLBACK操作。
提交就要特別注意了。BEGIN TRAN 建立事務3個,則必須COMMIT TRAN 提交事務3次,才能確保事務數被完整提交。可以通過@@TRANCOUNT來檢視當前事務數。一旦儲存過程沒有完整提交事務,則可能出現事務鎖表的情況!如果建立事務的程式銷燬了,即使有未提交的事務,應該也銷燬,算回滾了吧?

相關文章