TransactionScope 如何回滚事务?

Posted

技术标签:

【中文标题】TransactionScope 如何回滚事务?【英文标题】:How does TransactionScope roll back transactions? 【发布时间】:2010-10-04 10:03:33 【问题描述】:

我正在编写一个集成测试,我将在其中将一些对象插入到数据库中,然后检查以确保我的方法是否检索到这些对象。

我与数据库的连接是通过 NHibernate...我通常创建此类测试的方法是执行以下操作:

NHibernateSession.BeginTransaction();

//use nhibernate to insert objects into database
//retrieve objects via my method
//verify actual objects returned are the same as those inserted

NHibernateSession.RollbackTransaction();

但是,我最近发现 TransactionScope 显然可以用于此目的...

部分example code I've found如下:

public static int AddDepartmentWithEmployees(Department dept)


    int res = 0;

    DepartmentAdapter deptAdapter = new DepartmentAdapter();
    EmployeeAdapter empAdapter = new EmployeeAdapter();
    using (TransactionScope txScope = new TransactionScope())
    

        res += deptAdapter.Insert(dept.DepartmentName);
        //Custom method made to return Department ID 
        //after inserting the department "Identity Column"
        dept.DepartmentID = deptAdapter.GetInsertReturnValue();
        foreach(Employee emp in dept.Employees)
        

            emp.EmployeeDeptID = dept.DepartmentID;
            res += empAdapter.Insert(emp.EmployeeName, emp.EmployeeDeptID);

        
        txScope.Complete();

    
    return res;


我相信如果我不包含txScope.Complete() 行,插入的数据将被回滚。但不幸的是,我不明白这怎么可能……txScope 对象如何跟踪deptAdapterempAdapter 对象及其在数据库中的事务。

我觉得我在这里遗漏了一些信息......我真的能够通过使用TransactionScope 包围我的代码来替换我的BeginTransaction()RollbackTransaction() 调用吗?

如果不是,那么TransactionScope 如何回滚事务?

【问题讨论】:

我从未使用过 NHibernate,但也许 this link 会帮助你。 如果您正在寻找一种更好的方法来管理您的 NHibernate 会话以将操作分组到事务中,您可能想查看我关于该主题的博客文章 dotnetchris.wordpress.com/2009/01/27/… 【参考方案1】:

本质上,TransactionScope 不会跟踪您的适配器,它所做的是跟踪数据库连接。当您打开数据库连接时,连接将查看是否存在环境事务(事务范围),如果有,则加入该事务。注意,如果有多个连接到同一个 SQL 服务器,这将升级为分布式事务。

自从您使用 using 块后会发生什么,您确保即使发生异常也会调用 dispose。因此,如果在 txScope.Complete() 之前调用 dispose,则 TransactionScope 将告诉连接回滚其事务(或 DTC)。

【讨论】:

TransactionScope 只跟踪线程上的当前事务,并在需要时根据模型对其进行修改(需要、需要新的等)。事务只是通知任何与它一起登记的东西,而不仅仅是数据库连接。 我认为这并不完全正确。我对 TransactionScope 的源代码进行了部分跟踪,并且还看到了这个msdn.microsoft.com/en-us/library/ms172152(v=vs.90).aspx,上面写着“如果它没有创建事务,那么只要 CommittableTransaction 对象的所有者调用 Commit 就会发生提交。那时事务管理器调用资源管理器并根据是否在 TransactionScope 对象上调用 Complete 方法通知它们提交或回滚。”源跟踪也表明了这种行为。 我发现这个 SO Q&A 很有用:IEnlistmentNotification 我还不清楚。似乎在事务范围内调用方法的对象必须与事务机制合作。他们必须寻找系统的 Commit/Rollback 通知,并且能够自行回滚,因为他们是在需要时执行回滚的人(如果执行了文件删除,显然我们不能神奇地回滚它,除非我们采取一些预防措施)。 SQL 服务器操作似乎也是合作的。但是.Net 中还有其他合作对象吗?以及如何编写一个合作的类?文档?【参考方案2】:

TransactionScope class 与线程特定的Transaction class 一起使用。

TransactionScope被创建时,它会检查线程是否有Transaction;如果存在,则使用它,否则,它会创建一个新的并将其推入堆栈。

如果它使用现有的,那么它只会增加一个发布计数器(因为你必须在上面调用Dispose)。在上一个版本中,如果没有提交 Transaction,它会回滚所有工作。

至于为什么类似乎神奇地知道事务,这留给那些希望使用此模型的类作为实现细节。

当您创建 deptAdapteremptAdapter 实例时,它们会检查线程上是否存在当前事务(Transaction 类上的静态 Current property)。如果有,那么它将自己注册到Transaction,以参与提交/回滚序列(由Transaction 控制,并可能传播到不同的事务协调器,例如内核、分布式等)。

【讨论】:

它如何与在范围内创建的 SqlConnection(s) 一起工作? SqlConnection 类是否在内部使用反过来与 TransactionScope 一起登记的 Transaction 类?还是直接加入 TLS?

以上是关于TransactionScope 如何回滚事务?的主要内容,如果未能解决你的问题,请参考以下文章

探索逻辑事务 TransactionScope

如果在提交时抛出异常,C# TransactionScope 会回滚吗?

TransactionScope事务

TransactionScope事务操作

TransactionScope:避免分布式事务

复习三层架构