C# TransactionScope 如何回滚事务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/494550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:36:05  来源:igfitidea点击:

How does TransactionScope roll back transactions?

c#.netnhibernatetransactionstransactionscope

提问by mezoid

I'm writing an integration test where I will be inserting a number of objects into a database and then checking to make sure whether my method retrieves those objects.

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

My connection to the database is through NHibernate...and my usual method of creating such a test would be to do the following:

我与数据库的连接是通过 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();

However, I've recently found out about TransactionScopewhich apparently can be used for this very purpose...

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

Some example code I've foundis as follows:

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

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;

}

I believe that if I don't include the line txScope.Complete()that the data inserted will be rolled back. But unfortunately I don't understand how that is possible... how does the txScopeobject keep a track of the deptAdapterand empAdapterobjects and their transactions on the database.

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

I feel like I'm missing a bit of information here...am I really able to replace my BeginTransaction()and RollbackTransaction() calls by surrounding my code using TransactionScope?

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

If not, how then does TransactionScopework to roll back transactions?

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

采纳答案by JoshBerke

Essentially TransactionScope doesn't track your Adapter's, what it does is it tracks database connections. When you open a DB connection the connections will looks if there is an ambient transaction (Transaction Scope) and if so enlist with it. Caution if there are more the one connection to the same SQL server this will escalate to a Distribtued Transaction.

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

What happens since you're using a using block you are ensuring dispose will be called even if an exception occurs. So if dispose is called before txScope.Complete() the TransactionScope will tell the connections to rollback their transactions (or the DTC).

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

回答by casperOne

The TransactionScopeclassworks with the Transactionclass, which is thread-specific.

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

When the TransactionScopeis created, it checks to see if there is a Transactionfor the thread; if one exists then it uses that, otherwise, it creates a new one and pushes it onto the stack.

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

If it uses an existing one, then it just increments a counter for releases (since you have to call Disposeon it). On the last release, if the Transactionwas not comitted, it rolls back all the work.

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

As for why classes seem to magically know about transactions, that is left as an implementation detail for those classes that wish to work with this model.

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

When you create your deptAdapterand emptAdapterinstances, they check to see if there is a current transaction on the thread (the static Currentpropertyon the Transactionclass). If there is, then it registers itself with the Transaction, to take part in the commit/rollback sequence (which Transactioncontrols, and might propogate to varying transaction coordinators, such as kernel, distributed, etc.).

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