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

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

问题是我使用 TransactionScope 发生异常:

  

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

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

  

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

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

有帮助吗?

解决方案 8

嗯,当我更改 TransactionScopeOption时似乎有效到“抑制”:

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

每个人都知道为什么吗?

其他提示

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

  

控制面板 - >行政的   工具 - >组件服务 - >组件   Serivces-> Computes->我的电脑 - >对   点进>属性 - > MSDTC->安全   构造

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

  

HKLM \ SOFTWARE \政策\微软\窗户   NT \ RPCRestrictRemoteClients = 0   HKLM \ Software \ Policies \ Microsoft \ Windows NT \ RPCEnableAuthEpResolution = 1

让一切运转起来。

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

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

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

排除MSDTC问题

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

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

"如果您正在使用Entity Framework with Transactions,Entity Framework会自动打开和关闭每个数据库调用的连接。因此,在使用事务时,您尝试通过多个连接传播事务。这提升到了MSDTC。“

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

也许这是您的答案: MSSQL错误'基础提供商在Open'上失败了

如果你想运行一些可能失败的代码,但是你不想因为失败而中止事务,那么强制执行该事务是很有用的。

您需要问自己的问题如下: 您是否在transactionScope中访问了多个持久资源?我的意思是,你打开超过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

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

如果未启动Distributed Transaction Coordinator服务,则Entity框架无法连接到数据库。 打开并启动分布式事务处理协调器

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top