TransactionScope导致阻塞?

Jon*_*nas 4 c# transactions transactionscope

我正在针对数据库编写一些单元测试,我们正在使用事务来确保我们的测试数据最终被删除.

我遇到了一个问题,我正在测试的方法正在使用自己的TransactionScope对象,而且在访问数据库时它似乎是阻塞的.

这是我的测试的基类:

BaseScope = new CommittableTransaction(new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUnCommitted, Timeout = new System.TimeSpan(0, 5, 0) });
Run Code Online (Sandbox Code Playgroud)

然后在我正在测试的方法内部,它确实:

using (TransactionScope scope = new TransactionScope())
Run Code Online (Sandbox Code Playgroud)

第二次范围内的代码第一次触及数据库,它就会挂起.我有解决这个问题的方法吗?

djn*_*jna 6

如果您正在使用数据库,那么您没有进行单元测试,而您遇到的问题是真正的单元测试使用Mocks和Stubs的原因之一.

现在你正在做的测试是非常有价值的,在某些情况下我实际上会做它们而不是单元测试.我标记了这种早期集成测试(EIT).这里的关键点是,在使用真实的东西而不是单元测试模拟时,我们会发现一类全新的错误.而关键在于Real Thing.一旦你伪造了具有人工交易范围等的环境,你就会失去EIT的大部分好处,因为你没有捕捉到微妙的交互错误,或者(如你的情况)引入人为问题.

我会找到一种方法来快速使用足够的测试数据填充数据库,并将其恢复到测试之外的状态."重置为已知状态"脚本对于这些类型的测试非常有用.


LBu*_*kin 5

嵌套TransactionScope实例时,最终可能会使用分布式事务,而不是简单的本地事务.这种行为在使用的数据库之间有所不同.例如,SQLServer 2008不会升级到DTX,除非实际涉及多个数据库.另一方面,Oracle将始终升级到分布式事务,因为它不支持单个本地事务的共享连接.

根据TransactionScopeOption您使用的数据库和内容,您可能会遇到死锁.发生这种情况是因为DTX通常需要表锁以确保它们可以原子方式提交.例如,在Oracle中,如果在完成之前启动DTX并崩溃或丢失连接,则最终可能会出现"疑难分布式事务".此"In Doubt"事务可能会锁定一个或多个表,阻止其他会话修改它们,直到DBA ROLLBACK FORCE对挂起的事务ID 执行命令.某些数据库(如SQLServer)尝试检测此类死锁并终止其中一个违规事务......但这可以保证发生.

我会建议你选择以下两个选项之一:

  1. 确定是否确实需要编写打到数据库的测试.通常,您可以使用模拟或存根来避免编写更改然后回滚数据库的测试.避免这些问题是有道理的,因为它既可以加快测试速度,又可以消除对它们的潜在依赖性.但是,有时你不能这样做.
  2. 如果您确实需要针对数据库测试逻辑,请考虑修改代码,以便所有方法使用相同的数据库连接来执行SQL.这将消除分布式事务的创建,并有望克服您的问题.

您可能还想查看数据库的挂起事务视图(在Oracle中,它在SQLServer中称为PENDING_TRANS $ ...,它是XACT_STATE()函数).