访问当前事务
适用范围:SQL Server
如果事务在输入 SQL Server 上运行的公共语言运行时 (CLR) 代码时处于活动状态,则事务将通过 System.Transactions.Transaction 类公开。 Transaction.Current 属性用于访问当前事务。 在大多数情况下,不必显式访问事务。 对于数据库连接,ADO.NET 在调用 Connection.Open 方法时自动检查 Transaction.Current,并在该事务中以透明方式登记连接(除非 enlist 关键字在连接字符串中设置为 false)。
你可能希望在以下方案中直接使用 Transaction 对象:
如果您要登记未自动登记的资源或因为某个原因而未在初始化期间登记的资源。
如果您要显式登记事务中的资源。
如果您要从存储过程或函数的内部终止外部事务。 在这种情况下,使用 TransactionScope。 例如,以下代码将回滚当前事务:
using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOptions.Required)) { }
本主题的其余内容介绍取消外部事务的其他方式。
取消外部事务
可以用以下方式从托管过程或函数取消外部事务:
通过使用输出参数,托管过程或函数可以返回值。 调用 Transact-SQL 过程可以检查返回的值,如果适用,则执行 ROLLBACK TRANSACTION。
托管过程或函数可以引发自定义异常。 调用 Transact-SQL 过程可以捕获托管过程或函数在 try/catch 块中引发的异常,并执行 ROLLBACK TRANSACTION。
如果满足特定条件,托管过程或函数可以通过调用 Transaction.Rollback 方法来取消当前事务。
在托管过程或函数中调用它时, 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 过程,托管代码执行将完成。 执行完托管代码时,将引发另一个异常:
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 方法从托管过程回滚的事务的示例。 请注意托管代码中 Transaction.Rollback 方法周围的 try/catch 块。 Transact-SQL 脚本创建程序集和托管存储过程。 请注意, EXEC uspRollbackFromProc 语句包装在 try/catch 块中,以便捕获托管过程完成执行时引发的异常。
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();
}
}
};
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Transactions
Partial Public Class StoredProcedures
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub uspRollbackFromProc ()
Using connection As New SqlConnection("context connection=true")
' Open the connection.
connection.Open()
Dim successCondition As Boolean
successCondition = False
' Success condition is met.
If successCondition Then
SqlContext.Pipe.Send("Success condition met in procedure.")
' 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.
Dim trans As Transaction
trans = Transaction.Current
trans.Rollback()
Catch ex As SqlException
' Catch the exception instead of throwing it.
' This allows the connection to close correctly.
End Try
End If
' Close the connection.
connection.Close()
End Using
End Sub
End Class
Transact-SQL
--Register assembly.
CREATE ASSEMBLY TestProcs FROM 'C:\Programming\TestProcs.dll'
Go
CREATE PROCEDURE uspRollbackFromProc AS EXTERNAL NAME TestProcs.StoredProcedures.uspRollbackFromProc
Go
-- Execute procedure.
BEGIN TRY
BEGIN TRANSACTION
-- Perform other actions.
Exec 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 TRANSACTION
PRINT N'Transaction rolled back.'
END CATCH
Go
-- Clean up.
DROP Procedure uspRollbackFromProc;
Go
DROP ASSEMBLY TestProcs;
Go