TransactionScope如何回滚事务?


99

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

我与数据库的连接是通过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,显然可以用于此目的...

我发现的一些示例代码如下:

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对象及其事务。

我感觉好像在这里丢失了一些信息...我真的能够通过使用?包围我的代码来替换我BeginTransaction()和(RollbackTransaction()调用TransactionScope

如果没有,那么如何TransactionScope回滚事务?


我从未使用过NHibernate,但也许此链接会为您提供帮助。

如果你正在寻找一种更好的方式来管理你的NHibernate会话组操作进入交易你可能想看看关于这一主题我的博客文章dotnetchris.wordpress.com/2009/01/27/...
克里斯Marisic

Answers:


107

本质上,TransactionScope不会跟踪适配器的,它会跟踪数据库连接。当您打开数据库连接时,连接将查看是否存在环境事务(事务作用域),如果有,请注册它。注意,如果到同一SQL Server的连接只有一个以上,它将升级为Distribtued Transaction。

由于您正在使用using块,因此会发生什么情况,您可以确保即使发生异常也将调用dispose。因此,如果在txScope.Complete()之前调用dispose,那么TransactionScope将告诉连接回滚其事务(或DTC)。


10
TransactionScope除了跟踪线程上的当前事务外,不跟踪任何内容,并根据需要(基于模型,需要,需要新模型等)对其进行修改。事务会简单地通知所有征用它的东西,而不仅仅是数据库连接。
casperOne

1
我认为这并非完全正确。我对TransactionScope的源代码进行了部分跟踪,并且还看到了msdn.microsoft.com/zh-cn/library/ms172152(v=vs.90).aspx ,其中显示“如果未创建事务,只要CommittableTransaction对象的所有者调用了Commit,就会发生提交。这时,事务管理器将调用资源管理器,并根据是否在TransactionScope对象上调用Complete方法来通知资源管理器进行提交或回滚。” 源跟踪也指示此行为。
user44298 2011年

我发现这样的问题解答
mungflesh 2014年

我仍然不清楚。似乎在事务范围内使用方法调用的对象必须与Transaction机制配合。他们必须寻找系统的Commit / Rollback通知,并且能够回滚自己,因为它们是在需要时执行回滚的对象(如果执行了文件删除,显然,除非采取了删除操作,否则我们无法神奇地回滚它)一些预防措施)。看来SQL Server操作是协作的。但是.Net中还有其他合作对象吗?以及如何编写一个合作的类?文档?
分钟

54

TransactionScope的工作原理与Transaction阶级,这是线程特定的。

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

如果它使用现有的计数器,那么它只会增加一个计数器来发布(因为您必须调用Dispose它)。在最后一个发行版中,如果Transaction未提交,它将回滚所有工作。

至于为什么类似乎神奇地了解事务,对于那些希望与该模型一起使用的类,这留作实现细节。

当您创建deptAdapteremptAdapter实例,他们检查,看看是否有线程(静态上当前事务Current属性Transaction类)。如果存在,则它向进行注册Transaction,以参与提交/回滚序列(该序列Transaction控制,并且可能会推广至各种事务协调器,例如内核,分布式等)。


4
如何与在范围内创建的SqlConnection一起使用?SqlConnection类是否在内部使用交易类,而交易类又会在TransactionScope中入伍?还是直接加入TLS?
卡基拉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.