使用 System.Transactions

适用范围:SQL Server

System.Transactions 命名空间提供与 ADO.NET 和 SQL Server 公共语言运行时 (CLR) 集成完全集成的事务框架。 System.Transactions.TransactionScope 类通过在分布式事务中隐式登记连接来生成代码块事务。 必须在 TransactionScope标记的代码块末尾调用 Complete 方法。 当程序执行离开代码块时,将调用 Dispose 方法,导致未调用 Complete 方法时 停止事务。 如果引发导致代码离开范围的异常,则事务被视为已停止。

建议使用 using 块来确保退出 using 块时,TransactionScope 对象上调用 Dispose 方法。 无法提交或回滚挂起的事务可能会严重降低性能,因为 TransactionScope 的默认超时为 1 分钟。 如果不使用 using 语句,则必须在 Try 块中执行所有工作,并在 Finally 块中显式调用 Dispose 方法。

如果在 TransactionScope中发生异常,则事务将标记为不一致且被放弃。 释放 TransactionScope 时,它会回滚。 如果未发生异常,则提交参与的事务。

仅当访问本地和远程数据源或外部资源管理器时,才应使用 TransactionScope,因为 TransactionScope 始终会导致事务升级,即使仅在上下文连接中使用。

默认情况下,TransactionScope 类创建 System.Transactions.Transaction.IsolationLevelSerializable 的事务。 根据您的应用程序,您可能希望考虑降低隔离级别,以避免在应用程序中发生争用激烈的情况。

注意

建议您在分布式事务内针对远程服务器仅执行更新、插入和删除操作,因为这些操作占用大量数据库资源。 如果要在本地服务器上执行该操作,则不需要分布式事务,并且本地事务就足够了。 SELECT 语句可能会不必要的锁定数据库资源,在某些情况下,可能需要使用事务进行选择。 应在事务范围之外执行任何非数据库工作,除非它涉及其他事务资源管理器。

尽管事务范围内的异常会阻止事务提交,但 TransactionScope 类没有设置回滚代码在事务本身范围之外所做的任何更改。 如果需要在回滚事务时采取一些操作,则必须编写自己的 System.Transactions.IEnlistmentNotification 接口实现,并在事务中显式登记。

例子

若要使用 System.Transactions,必须具有对 System.Transactions.dll 文件的引用。

以下代码演示如何创建可针对两个不同的 SQL Server 实例升级的事务。 这些实例由两个不同的 System.Data.SqlClient.SqlConnection 对象表示,这些对象包装在 TransactionScope 块中。 该代码使用 using 语句创建 TransactionScope 块,并打开第一个连接,该连接会自动在 TransactionScope中登记。 该事务最初作为轻型事务登记,而不是完全分布式事务。 代码假定存在条件逻辑(为简洁起见省略)。 仅当需要时,它才会打开第二个连接,并在 TransactionScope中登记它。

打开该连接后,事务将自动提升为完全分布式事务。 然后,代码将调用提交事务的 TransactionScope.Complete。 代码在退出连接的 using 语句时释放两个连接。 TransactionScopeTransactionScope.Dispose 方法在 TransactionScopeusing 块终止时自动调用。 如果在 TransactionScope 块中的任何时间点引发异常,则不会调用 Complete,分布式事务在释放 TransactionScope 时回滚。

using (TransactionScope transScope = new TransactionScope())
{
    using (SqlConnection connection1 = new
       SqlConnection(connectString1))
    {
        // Opening connection1 automatically enlists it in the
        // TransactionScope as a lightweight transaction.
        connection1.Open();

        // Do work in the first connection.

        // Assumes conditional logic in place where the second
        // connection will only be opened as needed.
        using (SqlConnection connection2 = new
            SqlConnection(connectString2))
        {
            // Open the second connection, which enlists the
            // second connection and promotes the transaction to
            // a full distributed transaction.
            connection2.Open();

            // Do work in the second connection.
        }
    }
    //  The Complete method commits the transaction.
    transScope.Complete();
}