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
对象如何跟踪deptAdapter
和empAdapter
对象及其在数据库中的事务。
我觉得我在这里遗漏了一些信息......我真的能够通过使用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
,它会回滚所有工作。
至于为什么类似乎神奇地知道事务,这留给那些希望使用此模型的类作为实现细节。
当您创建 deptAdapter
和 emptAdapter
实例时,它们会检查线程上是否存在当前事务(Transaction
类上的静态 Current
property)。如果有,那么它将自己注册到Transaction
,以参与提交/回滚序列(由Transaction
控制,并可能传播到不同的事务协调器,例如内核、分布式等)。
【讨论】:
它如何与在范围内创建的 SqlConnection(s) 一起工作? SqlConnection 类是否在内部使用反过来与 TransactionScope 一起登记的 Transaction 类?还是直接加入 TLS?以上是关于TransactionScope 如何回滚事务?的主要内容,如果未能解决你的问题,请参考以下文章