ADO.NET 实体框架中的事务的 MSDTC 问题

发布于 2024-08-08 14:51:46 字数 1393 浏览 2 评论 0原文

在我们当前的项目中,我们使用 ADO.NET 实体框架作为应用程序的数据层。有些任务需要在事务中运行,因为数据库中有很多工作要做。我正在使用 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 有关(微软分布式事务协调器)。当我更改 MSDTC 的安全配置时,会引发另一个异常:

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

无论 MSDTC 配置如何,TransactionScope 将导致错误。 有人知道这里出了什么问题吗?

in our current project we are using ADO.NET Entity Framework as data layer for the application. There are some tasks which require to run in a transaction because there's a lot of work to do in the database. I am using a TransactionScope to surround those tasks.

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

The problem is as soon as i am using an TransactionScope an exception occurs:

System.Data.EntityException: The underlying provider failed on Open. ---> System.Transactions.TransactionManagerCommunicationException: Communication with the underlying transaction manager has failed. ---> System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.

It seems that this error has to do something with the MSDTC (Microsoft Distributed Transaction Coordinator). When I change the security configuration of MSDTC another exception is thrown:

System.Data.EntityException: The underlying provider failed on Open. ---> System.Transactions.TransactionManagerCommunicationException: Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.

However MSDTC is configured, the TransactionScope will cause an error.
Does somebody know whats going wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

旧情别恋 2024-08-15 14:51:46

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

控制面板->行政
工具->组件服务->组件
服务->计算->我的电脑->右侧
单击->属性->MSDTC->安全
配置

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

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

让一切启动并运行。

By default MSDTC has network access disabled. To get it working you should go to

Control Panel-> Administrative
Tools->Component Services->Component
Serivces->Computes->My computer->Right
click->Properties->MSDTC->Security
Configuration

and check following checkboxes Network DTC Access, Allow Inbound, Allow Outbound. Authentification should be chosen according to you environment. You might also want to take a look at DTCPing tool to debug distributed transactions. To give you a shortcut - you may need to modify you registry:

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

to get everything up and running.

扬花落满肩 2024-08-15 14:51:46

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

Yes, it works using Supress, because you are telling it to supress or ignore the ambient transaction and create a new local transaction. Since the transaction is local it is not a distributed transaction so its not using MSDTC, but you probably shouldn't use Suppress and should use Required instead.

离笑几人歌 2024-08-15 14:51:46

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

This means it is suppressing any Transaction that might be in effect currently when you enter your code block, so any updates your code makes will not rollback if the outer "ambient" transaction decides to rollback.

↘人皮目录ツ 2024-08-15 14:51:46

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

使用 MSDTC 进行故障排除

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

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

This is the article we used in resolving our own, similar issue:

Troubleshooting Problems with MSDTC

This is basically an addendum to Nikolay R's answer. He already covered some of the suggestions listed in the article.

Note: The article is part of the Biztalk documentation, but it can apply to anything using MSDTC.

冰葑 2024-08-15 14:51:46

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

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

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

"If you are using Entity Framework with Transactions, Entity Framework automatically opens and closes a connection with each database call. So when using transactions, you are attempting to spread a transaction out over multiple connections. This elevates to MSDTC."

You can pass in your database context to callee class or function in your transaction.

Maybe this is your answer: MSSQL Error 'The underlying provider failed on Open'

删除会话 2024-08-15 14:51:46

如果您想要运行一些可能会失败的代码,但又不想因为失败而中止事务,则抑制事务非常有用。

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

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

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

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

//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

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

Supressing the transaction is usefull if you want to run some code that might fail, but you don't want to abort the transaction because of that fail.

The question you need to ask yourself is the following:
Are you accessing more than 1 durable resource in your transactionScope? I mean, do you open connections to more than 1 DB?

This is an important question as the transaction will be escalated towards DTC if you access more than 1 durable resource.

At least two durable resources that support single-phase notifications are enlisted in the transaction. For example, enlisting a single connection with does not cause a transaction to be promoted. However, whenever you open a second connection to a database causing the database to enlist, the System.Transactions infrastructure detects that it is the second durable resource in the transaction, and escalates it to an MSDTC transaction.
Source: MSDN

If that's the case, you can solve your problem by nesting your transactionscopes correctly, example:

//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();

}

You can find more info about TransactionScopes, how nesting works,... on MSDN.

I hope this answer can help people in the future.

神也荒唐 2024-08-15 14:51:46

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

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

If Distributed Transaction Coordinator service is not started, Entity framework can not connect to database.
Open and start the Distributed Transaction Coordinator

Services -> Distributed Transaction Coordinator

错爱 2024-08-15 14:51:46

嗯,当我更改 TransactionScopeOption 到“打压”:

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

大家知道为什么吗?

Hmm, it seems to work when i change the TransactionScopeOption to "Suppress":

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

Does everyone know why?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文