代码之家  ›  专栏  ›  技术社区  ›  Alexander

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

  •  6
  • Alexander  · 技术社区  · 15 年前

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

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

    问题是我一使用 交易范围 出现异常:

    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,则 交易范围 将导致错误。 有人知道这里出了什么事吗?

    8 回复  |  直到 9 年前
        1
  •  7
  •   Nikolay R    15 年前

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

    控制面板-管理 工具->组件服务->组件 系列->计算->我的计算机->右 单击->属性->msdtc->安全性 配置

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

    hklm \软件\策略\microsoft\windows nt\rpcrestrictremoteclients=0 hklm\software\policies\microsoft\windows nt\rpcenableauthepresolution=1

    让一切正常运转。

        2
  •  3
  •   Bill    13 年前

    是的,它使用supress工作,因为您告诉它抑制或忽略环境事务,并创建一个新的本地事务。因为事务是本地的,所以它不是分布式事务,所以它不使用msdtc,但是您可能不应该使用suppress,而应该使用required。

        3
  •  0
  •   SpockMonster    15 年前

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

        4
  •  0
  •   Community holdenweb    7 年前

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

    Troubleshooting Problems with MSDTC

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

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

        5
  •  0
  •   Community holdenweb    7 年前

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

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

    也许这就是你的答案: MSSQL Error 'The underlying provider failed on Open'

        6
  •  0
  •   Bram Van Strydonck    9 年前

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

    你需要问自己的问题是: 您是否正在访问TransactionScope中的1个以上持久资源?我的意思是,你打开超过1分贝的连接吗?

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

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

    如果是这样,您可以通过正确嵌套TransactionScope来解决问题,例如:

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

    }

    您可以找到有关TransactionScope、嵌套工作方式等的更多信息…在 MSDN .

    我希望这个答案能在将来帮助人们。

        7
  •  0
  •   aydnahmet    9 年前

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

    服务--分布式事务处理协调器

        8
  •  -2
  •   Alexander    15 年前

    嗯,当我改变 TransactionScopeOption “压制”:

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

    大家都知道为什么吗?