.NET TransactionScope and MSDTC

6

我的代码中有需要处理的事务:

using (var scope = new TransactionScope())
{
  repo1.SaveSomething();
  repo2.SaveAnythingElse();
  scope.Complete();
}

在repo1和repo2内部,它们使用using创建自己的db context,并且在完成后释放它们,事务运行得很好。 现在我添加了另一段代码,却开始抛出异常: “底层提供程序无法打开(EntityFramework)已禁用分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具,在MSDTC的安全配置中启用DTC以进行网络访问。(System.Transactions)事务管理器已禁用其对远程/网络事务的支持。” 我发现当在同一个sql server数据库内的事务中打开连接时,它需要使用MSDTC组件来处理。所以我更改了代码如下:
using (var scope = new TransactionScope(TransactionScopeOption.Required, 
new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted }))
{
   ....
   scope.Complete();
}

现在异常已经消失了。

我的问题:

  • 为什么之前代码中使用的事务从未丢弃异常?
  • 为什么新代码会丢弃异常?
  • 更改后为什么不再丢弃异常?

我认为这些问题很容易 :) 任何帮助将不胜感激!


什么数据库?事务提交是由提供程序决定的行为。 - David Browne - Microsoft
MS-Sql服务器,兼容级别SQL Server 2012(110)。 - Zoltan Hernyak
1个回答

8

1) 对于您的TransactionScope,绝对应该使用ReadCommitted而不是默认的Serializable,但这与您的问题无关,请参见此处

2) 当您有一个活动的TransactionScope时,每次打开SqlConnection时,它将被注册在该事务中。如果没有其他资源参与事务,则SqlClient将开始一个本地或“轻量级”事务。这不涉及MSTDC;它只是在打开的SqlConnection上启动的普通SQL Server事务。

如果您关闭那个SqlConnection(或Dispose包含它的EF DbContext),则该连接将返回到连接池。但它与其他池化连接隔离,并且一直挂起,直到事务完成或回滚。

如果您在相同的TransactionScope内以完全相同的ConnectionString打开新的SqlConnection,而不是获得一个新连接,连接池将只返回已经在事务中的现有连接。

如果您在相同的TransactionScope内使用不同的ConnectionString打开新的SqlConnection,或者当连接池中没有已经在事务中注册的连接时,将会获得一个新的SqlConnection并被注册进事务。但由于已经有了另一个SqlConnection在事务中注册,这将需要MSTDC创建一个真正的分布式事务。这称为“晋升”;您的“轻量级事务”被“晋升”为“分布式事务”。

因此,通过审核连接生命周期和ConnectionString的使用,查看为什么会在此处触发晋升。

换句话说,通过正确的ConnectionString使用和连接生命周期管理,您应该能够运行此代码:

using (var scope = new TransactionScope())
{
  repo1.SaveSomething();
  repo2.SaveAnythingElse();
  scope.Complete();
}

不触发分布式事务。


谢谢。我会检查我的代码。这意味着“ReadCommitted”不算数。那么 - 这是我代码中唯一的更改 - 为什么异常不再下降? - Zoltan Hernyak
第五段:“...或者当连接池中没有已在事务中注册的连接时...”肯定是在创建事务后第一次创建连接时会出现这种情况吧?而我们知道那个连接不会被提升。 - bornfromanegg
只有在您注册了“第二个”连接后,促销活动才会发生。 - David Browne - Microsoft
1
好的,所以我引用的那一部分是指如果你打开了一个,然后你打开第二个而没有关闭第一个,对吗?顺便说一下,这是我在两天内读到的关于TransactionScope最有用的东西。很难找到讲解细节的好材料,所以谢谢你。 - bornfromanegg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接