6

在我们当前的项目中,我们使用 ADO.NET Entity Framework 作为应用程序的数据层。有些任务需要在事务中运行,因为在数据库中有很多工作要做。我正在使用TransactionScope来围绕这些任务。

using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    // Do something...
    transactionScope.Complete();
}

问题是一旦我使用TransactionScope就会发生异常:

System.Data.EntityException:基础提供程序在打开时失败。---> System.Transactions.TransactionManagerCommunicationException:与底层事务管理器的通信失败。---> System.Runtime.InteropServices.COMException (0x80004005):对 COM 组件的调用已返回错误 HRESULT E_FAIL。

似乎此错误与MSDTC(Microsoft 分布式事务协调器)有关。当我更改 MSDTC 的安全配置时,会引发另一个异常:

System.Data.EntityException:基础提供程序在打开时失败。---> System.Transactions.TransactionManagerCommunicationException:分布式事务管理器 (MSDTC) 的网络访问已被禁用。请使用组件服务管理工具在 MSDTC 的安全配置中启用 DTC 以进行网络访问。

但是配置了 MSDTC,TransactionScope会导致错误。有人知道这里出了什么问题吗?

4

8 回答 8

7

默认情况下,MSDTC 已禁用网络访问。为了让它工作,你应该去

控制面板->管理工具->组件服务->组件服务->计算->我的电脑->右键->属性->MSDTC->安全配置

并选中以下复选框网络 DTC 访问、允许入站、允许出站。应根据您的环境选择身份验证。您可能还想看看DTCPing工具来调试分布式事务。为了给你一个快捷方式 - 你可能需要修改你的注册表:

HKLM\Software\Policies\Microsoft\Windows NT\RPCRestrictRemoteClients=0 HKLM\Software\Policies\Microsoft\Windows NT\RPCEnableAuthEpResolution=1

让一切正常运行。

于 2009-10-23T08:27:30.293 回答
3

是的,它使用抑制工作,因为您告诉它抑制或忽略环境事务并创建一个新的本地事务。由于事务是本地事务,因此它不是分布式事务,因此它不使用 MSDTC,但您可能不应该使用 Suppress,而应该使用 Required。

于 2011-03-11T21:01:22.340 回答
0

这意味着当您输入代码块时,它会抑制当前可能生效的任何事务,因此如果外部“环境”事务决定回滚,您的代码所做的任何更新都不会回滚。

于 2009-12-15T01:39:29.097 回答
0

这是我们用来解决我们自己的类似问题的文章:

解决 MSDTC 问题

这基本上是Nikolay R答案的附录。他已经涵盖了文章中列出的一些建议。

注意:本文是 Biztalk 文档的一部分,但它可以适用于使用 MSDTC 的任何内容。

于 2010-02-23T21:11:04.837 回答
0

“如果您将实体框架与事务一起使用,实体框架会自动打开和关闭与每个数据库调用的连接。因此,在使用事务时,您会尝试将事务分散到多个连接上。这会提升到 MSDTC。”

您可以将数据库上下文传递给事务中的被调用者类或函数。

也许这就是你的答案:MSSQL 错误“底层提供程序在打开时失败”

于 2013-05-29T03:05:45.690 回答
0

如果您想运行一些可能失败的代码,但又不想因为失败而中止事务,那么抑制事务很有用。

您需要问自己的问题如下:您是否在 transactionScope 中访问超过 1 个持久资源?我的意思是,你是否打开了超过 1 个 DB 的连接?

这是一个重要的问题,因为如果您访问超过 1 个持久资源,事务将升级为 DTC。

事务中至少包含两个支持单阶段通知的持久资源。例如,征用单个连接不会导致事务被提升。但是,每当您打开与数据库的第二个连接导致数据库登记时,System.Transactions 基础结构会检测到它是事务中的第二个持久资源,并将其升级为 MSDTC 事务。 资料来源:MSDN

如果是这种情况,您可以通过正确嵌套事务范围来解决问题,例如:

//Create rootScope
using(TransactionScope rootScope = new TransactionScope()) 
{ 
    using(TransactionScope scope2 = new 
    TransactionScope(TransactionScopeOption.Required)) 
    {
         //Do work on DB1
         ...

         //Complete this ambient transaction
         scope2.Complete();
    } 

    using(TransactionScope scope3 = new 
    TransactionScope(TransactionScopeOption.Required)) 
    {
         //Do work on DB2
         ...

         //Complete this ambient transaction
         scope3.Complete();
    } 

    //Complete rootScope
    //The whole transaction will only be committed if you call 
    //Complete on the rootScope
    rootScope.Complete();

}

您可以在MSDN上找到有关 TransactionScopes、嵌套如何工作等的更多信息。

我希望这个答案可以帮助未来的人。

于 2015-03-13T08:15:43.637 回答
0

如果分布式事务协调器服务没有启动,实体框架将无法连接到数据库。打开并启动分布式事务协调器

服务 -> 分布式事务协调器

于 2015-05-12T07:11:04.990 回答
-3

嗯,当我将TransactionScopeOption更改为“Suppress”时,它似乎有效:

using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress))
{
    ...
}

大家知道为什么吗?

于 2009-10-23T10:35:45.627 回答