Sql-Server
在使用 TRY CATCH 的 SQL Server 中送出事務的最佳實踐
在 SQL Server 程式碼塊中,放置送出事務的最佳位置是什麼?在 try catch 塊內還是在它外面?
例如,選項 A 或選項 B 是正確的方法還是它們是主觀的選擇?
選項 A
CREATE PROCEDURE DummyProc BEGIN TRY BEGIN TRANSACTION INSERT sometable(a, b) VALUES (@a, @b) INSERT sometable(a, b) VALUES (@b, @a) COMMIT TRANSACTION END TRY BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION DECLARE @msg nvarchar(2048) = error_message() RAISERROR (@msg, 16, 1) RETURN 55555 END CATCH
選項 B
CREATE PROCEDURE DummyProc BEGIN TRY BEGIN TRANSACTION INSERT sometable(a, b) VALUES (@a, @b) INSERT sometable(a, b) VALUES (@b, @a) END TRY BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION DECLARE @msg nvarchar(2048) = error_message() RAISERROR (@msg, 16, 1) RETURN 55555 END CATCH IF @@trancount > 0 COMMIT TRANSACTION
在選項 B 中,當它在塊外送出時是否有可能發生一些錯誤
TRY-CATCH
?
我發現這樣做的最佳方法是以下程式碼:
SET XACT_ABORT ON; BEGIN TRY BEGIN TRANSACTION /* Code goes here */ COMMIT TRANSACTION END TRY BEGIN CATCH DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @ErrorSeverity INT; DECLARE @ErrorState INT; SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); RAISERROR (@ErrorMessage, -- Message text. @ErrorSeverity, -- Severity. @ErrorState -- State. ); -- If >= SQL 2012 replace all code in catch block above with -- THROW; WHILE @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION; END END CATCH
注意使用 XACT_ABORT 確保錯誤被有效擷取,BEGIN 和 COMMIT 語句都在 TRY 塊內,以及 @@Trancount 的 WHILE - 這應該確保嵌套事務被回滾(並不總是適用)
THROW 語句還可以替換 2012 年以上 SQL 版本的 RAISERROR,以重新拋出擷取的異常/錯誤。
正如 Dan Guzman 在他的評論中所說,XACT_ABORT 對於擷取 TRY/CATCH 構造不會的錯誤很有用,包括超時、執行時排序錯誤等
選項A是正確的選擇。事務中的所有語句都可能工作,然後實際的 COMMIT 失敗,因此您將 COMMIT 保留在 TRY 塊中,以便擷取 COMMIT 的任何失敗,並且您可以優雅地處理此錯誤和回滾。
在 SE 上查看此答案。在您的範常式式碼中,如果我們假設其他使用者同時執行此過程,則 TRY 塊可能會成功完成,然後由於其他會話所做的更改而在 COMMIT 上失敗。