存取目前的交易
適用於:SQL Server
如果交易在 SQL Server 上執行的 Common Language Runtime (CLR) 程式代碼進入作用中時,交易會透過 System.Transactions.Transaction
類別公開。
Transaction.Current
屬性可用來存取目前的交易。 在大部分情況下,不需要明確存取交易。 針對資料庫連接,ADO.NET 會在呼叫 Connection.Open
方法時自動檢查 Transaction.Current
,並透明地登記該交易中的連接(除非連接字串中的 Enlist
關鍵詞設定為 false)。
您可能想要在下列案例中直接使用 Transaction
物件:
如果您想要登記未自動登記的資源,或基於某些原因未在初始化期間登記。
如果您想要在交易中明確登記資源。
如果您想要從預存程式或函式內終止外部交易。 在這裡情況下,您會使用 TransactionScope。 例如,下列程式代碼會回復目前的交易:
using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
本文的其餘部分說明其他取消外部交易的方式。
取消外部交易
您可以透過下列方式,從 Managed 程式或函式取消外部交易:
Managed 程式或函式可以使用輸出參數傳回值。 呼叫 Transact-SQL 程式可以檢查傳回的值,如果適當的話,請執行
ROLLBACK TRANSACTION
。Managed 程式或函式可以擲回自定義例外狀況。 呼叫 Transact-SQL 程式可以攔截 managed 程式或函式在 try/catch 區塊中擲回的例外狀況,並執行
ROLLBACK TRANSACTION
。如果符合特定條件,Managed 程式或函式可以藉由呼叫
Transaction.Rollback
方法來取消目前的交易。
在 Managed 程式或函式內呼叫 Transaction.Rollback
方法時,它會擲回具有模棱兩可錯誤訊息的例外狀況,而且可以包裝在 try/catch 區塊中。 錯誤訊息類似於下列輸出:
Msg 3994, Level 16, State 1, Procedure uspRollbackFromProc, Line 0
Transaction is not allowed to roll back inside a user defined routine, trigger or aggregate because the transaction is not started in that CLR level. Change application logic to enforce strict transaction nesting.
這是預期的例外狀況,而且需要 try/catch 區塊,程式代碼執行才能繼續。 如果沒有 try/catch 區塊,就會立即將例外狀況擲回呼叫 Transact-SQL 程式和 Managed 程式代碼執行完成。 當 Managed 程式代碼完成執行時,會引發另一個例外狀況:
Msg 3991, Level 16, State 1, Procedure uspRollbackFromProc, Line 1
The context transaction which was active before entering user defined routine, trigger or aggregate " uspRollbackFromProc " has been ended inside of it, which is not allowed. Change application logic to enforce strict transaction nesting. The statement has been terminated.
此例外狀況也是預期的,而且若要繼續執行,您必須在 Transact-SQL 語句周圍有 try/catch 區塊,以執行引發觸發程式的動作。 儘管擲回了兩個例外狀況,但交易仍會回復,且不會認可變更。
範例
下列程式代碼是使用 Transaction.Rollback
方法,從 Managed 程式復原的交易範例。 請注意managed程式代碼中 Transaction.Rollback
方法周圍的 try/catch 區塊。 Transact-SQL 腳本會建立元件和受控預存程式。
EXEC uspRollbackFromProc
語句會包裝在 try/catch 區塊中,讓 Managed 程式完成執行時擲回的例外狀況。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Transactions;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void uspRollbackFromProc()
{
using (SqlConnection connection = new SqlConnection(@"context connection=true"))
{
// Open the connection.
connection.Open();
bool successCondition = true;
// Success condition is met.
if (successCondition)
{
SqlContext.Pipe.Send("Success condition met in procedure.");
// Perform other actions here.
}
// Success condition is not met, the transaction will be rolled back.
else
{
SqlContext.Pipe.Send("Success condition not met in managed procedure. Transaction rolling back...");
try
{
// Get the current transaction and roll it back.
Transaction trans = Transaction.Current;
trans.Rollback();
}
catch (SqlException ex)
{
// Catch the expected exception.
// This allows the connection to close correctly.
}
}
// Close the connection.
connection.Close();
}
}
};
在 Transact-SQL 中註冊和執行元件
註冊元件。
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'; GO CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc; GO
執行程式。
BEGIN TRY BEGIN TRANSACTION; -- Perform other actions. EXECUTE uspRollbackFromProc; -- Perform other actions. PRINT N'Commiting transaction...'; COMMIT TRANSACTION; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS ErrorNum, ERROR_MESSAGE() AS ErrorMessage; PRINT N'Exception thrown, rolling back transaction.'; ROLLBACK; PRINT N'Transaction rolled back.'; END CATCH GO
清除您的環境。
DROP PROCEDURE uspRollbackFromProc; GO DROP ASSEMBLY TestProcs; GO