15

我们的团队遇到了一个问题,表现为:

底层提供者在 EnlistTransaction 上失败;无法访问已处置的对象。对象名称:“事务”。

在此处输入图像描述

这似乎在我们开始使用TransactionScope处理应用程序事务时就出现了。

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

在 System.Data.EntityClient.EntityConnection.EnlistTransaction(Transaction transaction) 在 System.Data.Objects.ObjectContext.EnsureConnection() 在 System.Data.Objects.ObjectContext.ExecuteStoreCommand(String commandText, Object[] 参数) 在 Reconciliation.Models。 BillLines.BillLines.Reconciliation.Interfaces.IBillLineEntities.ExecuteStoreCommand(String, Object[]) at Reconciliation.Models.Legacy.EntityDbEnvironment.ExecuteOracleSql(String sql) in EntityDbEnvironment.cs:第 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 :'<NULL>'"
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。

更新

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

....
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Information">
<TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated</TraceIdentifier>
<Description>TransactionScope Created</Description>
<AppDomain>BillLineGeneratorUI.exe</AppDomain>
<ExtendedData xmlns="http://schemas.microsoft.com/2004/03/Transactions/TransactionScopeCreatedTraceRecord">
<TraceSource>[Base]

如您所见,异常实际上阻止了日志完成。我能从中学到什么?有任何想法吗?

4

4 回答 4

7

我可以推荐使用 System.Transactions 跟踪源,而不是使用 MSDTC 跟踪工具(我觉得它非常简陋) - 只需在 web.config 中包含以下内容:
如果你打开日志文件,SvcTraceViewer.exe你会得到一个很好的视觉效果步骤的表示。

<configuration>
  <system.diagnostics>
   <trace autoflush="true" />
   <sources>
     <source name="System.Transactions" switchValue="Information">
       <listeners>
         <add name="tx"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData="C:\MyApp-transactions-log.svclog" />
       </listeners>
     </source>
   </sources>
  </system.diagnostics>
</configuration>

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

于 2014-07-14T18:58:58.190 回答
1

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

  • 您是否使用嵌套事务范围,因为如果由于某种原因,内部范围被回滚(在没有调用完成的情况下被处理),这将立即回滚导致错误的外部事务。使用 TransactionScopeOption.Required(RequiresNew 也可以,但 RequiresNew 有其他与死锁相关的问题,因此最好使用 Required)来解决这个问题

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

于 2014-07-16T09:55:56.410 回答
1

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

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

using(TransactionScope outerScope = new TransactionScope())
{
    // Execute query 1

    using(TransactionScope innerScope = new TransactionScope())
    {
        try
        {
            // Execute query 2
        }
        catch (Exception)
        {
        }

        innerScope.Complete();
    }

    outerScope.Complete();
}

现在,如果 try/catch 块内的查询 2 出现错误,您将在 try/catch 块中捕获异常并处理它,但这里有一个惊喜,当您尝试时,应用程序将在第 15 行抛出 ObjectDisposedException完成交易。这是因为 DTC 已经捕获了异常,尽管您已经处理了它,但已经由 .Net 代码处置的 TransactionScope 对象和事务已回滚。请注意,我所说的“对象”是因为两个 TransactionScope 对象都已被释放,因为它们是同一事务的一部分。

于 2014-07-17T12:58:17.493 回答
1

我们也有这个问题。解决它的最好方法似乎是打开一个新的数据库连接,只做事务中需要的事情。保持交易尽可能小总是好的。

 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) 也会消除该错误。

于 2013-06-06T08:48:17.223 回答