TransactionScope – 基础提供程序在EnlistTransaction上失败。 MSDTC被中止

我们的团队遇到的问题表现为:

基础提供程序在EnlistTransaction上失败; 无法访问已处置的对象。对象名称:’Transaction’。

在此处输入图像描述

一旦我们开始使用TransactionScope来处理我们的应用程序的事务,它似乎就出现了。

堆栈跟踪的顶部部分被捕获为:

在System.Data.EntityClient.EntityConnection.EnlistTransaction(事务事务)处的System.Data.Objects.ObjectContext.EnsureConnection()处于System.Data.Objects.ObjectContext.ExecuteStoreCommand(String commandText,Object [] parameters)处于Reconciliation.Models。在EntityDbEnvironment.cs中的Reconciliation.Models.Legacy.EntityDbEnvironment.ExecuteOracleSql(String sql)中的BillLines.BillLines.Reconciliation.Interfaces.IBillLineEntities.ExecuteStoreCommand(String,Object []):第41行

同时更新MSDTC日志,我使用此处的说明提取了该日志:

pid=7060 ;tid=7908 ;time=04/29/2013-16:38:30.269 ;seq=136 ;eventid=TRANSACTION_BEGUN ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction has begun, description :''" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:30.269 ;seq=137 ;eventid=RM_ENLISTED_IN_TRANSACTION ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"resource manager #1002 enlisted as transaction enlistment #1. RM guid = 'defc4277-47a6-4cd9-b092-93a668e2097b'" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=138 ;eventid=RECEIVED_ABORT_REQUEST_FROM_BEGINNER ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"received request to abort the transaction from beginner" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=139 ;eventid=TRANSACTION_ABORTING ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction is aborting" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=140 ;eventid=RM_ISSUED_ABORT ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"abort request issued to resource manager #1002 for transaction enlistment #1" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=141 ;eventid=RM_ACKNOWLEDGED_ABORT ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"received acknowledgement of abort request from the resource manager #1002 for transaction enlistment #1" pid=7060 ;tid=7908 ;time=04/29/2013-16:38:31.658 ;seq=142 ;eventid=TRANSACTION_ABORTED ;tx_guid=60f6390c-7570-488a-97a9-2c3912c4ca3e ;"TM Identifier='(null) '" ;"transaction has been aborted" 

正如您在RM_ENLISTED_IN_TRANSACTION被记录后的第二天看到RECEIVED_ABORT_REQUEST_FROM_BEGINNER

我们无法理解这个中止请求的来源,或者为什么要提出这个请求。 导致问题的SQL是一个简单的SELECT,我们可以通过我们的数据库客户端无问题地执行。

该应用程序大部分时间都在工作,只是偶尔会显示此问题。

我们正在使用Oracle 10.2.0.5.0和Entity Framework。

UPDATE

根据@Astrotrain的建议,我在System.Transactions上设置了日志记录。 产生的最终条目实际上是中途切断:

 ....     http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated TransactionScope Created BillLineGeneratorUI.exe  [Base] 

正如您所看到的,exception实际上阻​​止了日志的完成。 我可以从中学到什么? 有任何想法吗?

我没有使用MSDTC跟踪工具(我发现可怕的斯巴达),我建议使用System.Transactions跟踪源 – 只需在web.config中包含以下内容:
如果使用SvcTraceViewer.exe打开日志文件,您将获得步骤的可视化表示。

             

本身不是解决方案,但这可能会为您提供有关出错的更多信息。

正如您所提到的“应用程序大部分时间都在工作,只是偶尔显示此问题。” 通过这个我们可以得出结论,提供者确实支持分布式事务,原因是连接或处理中的一些其他间歇性故障。

  • 您是否正在使用嵌套事务作用域,因为如果由于某种原因,内部作用域被回滚(处理而不调用完成)会立即回滚导致错误的外部事务。 使用TransactionScopeOption.Required(RequiresNew也会这样做,但RequiresNew有与之关联的其他死锁相关问题,所以最好使用Required)来解决这个问题

  • 否则,可能是因为事务处于活动状态时的某些其他操作,并且在这种情况下解决使用IsolationLevel = IsolationLevel.ReadCommitted。

我们也有这个问题。 解决它的最佳方法似乎是打开一个新的数据库连接,只需执行事务中所需的操作。 保持交易尽可能小是永远好的。

  DatabaseContext db1 = new DatabaseContext(); doSomeDatabaseActions(db1); TransactionOptions transOpts = new TransactionOptions(); transOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable; using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transOpts)) { using (DatabaseContext db2 = new DatabaseContext()) { doDatabaseChecksWithLock(db2); doChanges(db2); db2.SaveChanges(); } scope.Complete(); } 

我们遇到了问题,没有引入第二个连接。 请注意,如果事务被放大(使doSomeDatabaseActions成为事务的一部分),则使用1连接(db1)也会出错。

这可能应该是一个评论,但它太大了。 我希望它有所帮助。

嵌套事务中最典型的错误之一是:

 using(TransactionScope outerScope = new TransactionScope()) { // Execute query 1 using(TransactionScope innerScope = new TransactionScope()) { try { // Execute query 2 } catch (Exception) { } innerScope.Complete(); } outerScope.Complete(); } 

现在,如果查询2位于try / catch块内部,则会出现错误,您将在try / catch块中捕获exception并处理它,但是这里有一个假设,当您尝试时,应用程序将在第15行抛出ObjectDisposedException完成交易。 这是因为DTC已经捕获了exception,虽然您已经处理了它,但已经回滚了已经由.Net代码处理的事务的TransactionScope对象。 请注意,我说过“对象”,这是因为两个TransactionScope对象都已被处理,因为它们是同一事务的一部分。