访问当前事务
适用范围: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();
}
}
};
在 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