Sql-Server

我們是否需要在 C# 程式碼和儲存過程中處理事務

  • January 29, 2017

我們真的需要c#中的事務處理以及數據庫儲存過程雙方嗎

C#:

Using(transaction with transaction scope)
{
    Execute stored proc;
    Transaction. Complete;
}

SQL儲存過程:

Create process
As
Begin try
   Begin transaction
   Commit
End try
Begin catch
   Rollback
End catch

首先,您應該始終在所有過程中進行適當的事務處理,以便它們是否被應用程式碼、另一個過程、在臨時查詢中單獨呼叫、通過 SQL 代理作業或其他方式呼叫都無關緊要. 但是單個 DML 語句或不進行任何修改的程式碼不需要顯式事務。所以,我推薦的是:

  • 始終具有 TRY / CATCH 結構,以便可以正確冒泡錯誤
  • 如果您有多個 DML 語句(因為單個語句本身就是一個事務),則可以選擇在下面的程式碼中包含 3 個事務處理部分。然而,除了在不需要的地方添加一些額外的程式碼之外,如果一個人更喜歡有一個一致的模板,那麼保留在 3 個與事務相關的 IF 塊中並沒有什麼壞處。但在那種情況下,我仍然建議不要為 SELECT-only(即只讀)過程保留 3 個與事務相關的 IF 塊。

在執行 2 個或更多 DML 語句時,您需要使用以下內容(如果希望保持一致,也可以對單個 DML 操作執行此操作):

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
   @Param  DataType
   ...
)
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT;

BEGIN TRY

   IF (@@TRANCOUNT = 0)
   BEGIN
       SET @InNestedTransaction = 0;
       BEGIN TRAN; -- only start a transaction if not already in one
   END;
   ELSE
   BEGIN
       SET @InNestedTransaction = 1;
   END;

   -- { 2 or more DML statements (i.e. INSERT / UPDATE / DELETE) }

   IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
   BEGIN
       COMMIT;
   END;

END TRY
BEGIN CATCH

   IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
   BEGIN
       ROLLBACK;
   END;

   DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
           @ErrorState     INT = ERROR_STATE(),
           @ErrorSeverity  INT = ERROR_SEVERITY();

   -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

   RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
   RETURN;

END CATCH;

僅執行 1 個 DML 語句或僅執行 SELECT 時,您只需執行以下操作即可:

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
   @Param  DataType
   ...
)
AS
SET NOCOUNT ON;

BEGIN TRY

   -- { 0 or 1 DML statements (i.e. INSERT / UPDATE / DELETE) }

END TRY
BEGIN CATCH

   DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
           @ErrorState     INT = ERROR_STATE(),
           @ErrorSeverity  INT = ERROR_SEVERITY();

   -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

   RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
   RETURN;

END CATCH;

**其次,**只有當您需要執行多個查詢/儲存過程並且它們都需要分組為原子操作時,您才應該在應用層處理事務。做單SqlCommand.Execute___只需要在try/catch中,而不是在Transaction中。

但是,只進行一次呼叫時,在應用層進行事務是否會受到傷害?如果它需要 MSDTC(Microsoft Distributed Transaction Coordinator),那麼在沒有明確需要時在應用層執行此操作對系統來說有點重。就個人而言,除非絕對必要,否則我更喜歡避免基於應用程序層的事務,因為它減少了孤立事務的可能性(如果在執行送出或回滾之前應用程式碼出現問題)。我還發現它有時會使調試某些情況變得更加困難。但話雖如此,我認為在製作單個proc時在應用層處理事務技術上沒有任何問題稱呼; 同樣,單個 DML 語句是它自己的事務,不需要任一層進行任何顯式事務處理。

引用自:https://dba.stackexchange.com/questions/93258