C# TransactionScope和Oracle的问题

C# TransactionScope和Oracle的问题,c#,oracle,transactionscope,C#,Oracle,Transactionscope,我们已经编写了一个C#3.5客户机,它使用ODP.NET与Oracle数据库(11g)通信 此应用程序有一个批处理过程,其中执行长时间运行的任务,在TransactionScope中对数据库进行各种调用 在我们的开发环境中一切进展顺利,但在我们的一个客户(拥有大量数据)的UAT环境中,出现两个交替的错误(有时一个,有时另一个…): 无法在分布式事务中登记 事务已中止。(内部异常:事务超时) 我们目前在交易中使用一天的超时时间(用于测试目的) 在UAT环境中运行上述进程会导致在大约10分钟后停止,

我们已经编写了一个C#3.5客户机,它使用ODP.NET与Oracle数据库(11g)通信

此应用程序有一个批处理过程,其中执行长时间运行的任务,在TransactionScope中对数据库进行各种调用

在我们的开发环境中一切进展顺利,但在我们的一个客户(拥有大量数据)的UAT环境中,出现两个交替的错误(有时一个,有时另一个…):

  • 无法在分布式事务中登记
  • 事务已中止。(内部异常:事务超时)
  • 我们目前在交易中使用一天的超时时间(用于测试目的)

    在UAT环境中运行上述进程会导致在大约10分钟后停止,出现上述异常之一,因此无法接近超时值

    下面是第二个错误的stacktrace片段:

    at System.Transactions.TransactionStatePromotedAborted.CreateAbortingClone(InternalTransaction tx)
       at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)
       at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
       at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
       at System.Transactions.TransactionScope.PushScope()
       at System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)
       at System.Transactions.TransactionScope..ctor()
       at Application.Domain.DataAccess.Oracle.EntityDaoBase`2.SaveItem(TEntity item, EntityReference`1 user)
    
    进程尝试将一个项保存到事务范围内的DB中,但stacktrace显示TransactionScope类的构造函数被命中,这意味着它创建了一个新的TransactionScope

    到目前为止我说的对吗

    因为我不太了解TransactionScope的内部工作方式,但似乎当您在范围内调用方法时,它将创建一个新的事务(假定从环境事务继承)

    如果我是对的,这个新事务是否会继承正确的超时(但默认超时),因此嵌套事务将导致这个超时异常

    如果没有,你有什么想法吗?另一方面,在环境事务中调用的方法中没有定义嵌套事务

    任何帮助都将不胜感激

    编辑1:

    函数的简化代码段:

    public void SomeLengthyBatchProcess()
    {
       using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
       {
           foreach (var item in Items)
           {
              SaveItemToDB(item);
           }
    
           transaction.Complete();
       }
    }
    
    public void SaveItemToDB(object item)
    {
       using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
       {
           // Performing data persistency here
    
           transaction.Complete();
       }
    }
    
    编辑2:

    好的,结果是,方法“SaveItemToDB”中有一个嵌套事务。在深入研究了一位同事编写的代码之后,我发现它定义了自己的TransactionScope,但没有选项和超时

    在修改此方法以使其具有相同的超时参数后,我在客户的服务器上再次运行了代码,但仍然没有成功(再次出现超时时事务中止错误)

    因此,我现在的问题如下:

  • 是否有必要为嵌套事务定义超时值,还是从环境事务继承超时值
  • 如果超时设置(除了我不知道的内部工作之外)对于所有事务范围都相同,并且超时值定义为1天(大约10分钟后发生异常),那么如何可能发生超时异常
  • 是否可以阻止Oracle为connectionstring相同的事务创建分布式事务
  • 分布式事务的额外开销是否会导致事务中止之类的异常
  • 我更新了代码片段,以便更好地反映情况

    (顺便说一句:第二个嵌套事务是必要的,因为DAL还分别持久化一些子项(如果存在),当然,如果在持久化子项时出现任何问题,整个项都应该回滚)


    希望有了这一点,它将更容易阐明这个问题

    您是否可以显示一段代码?从您提到的内容中,我唯一能找到的是与System.Transactions相关的内容。讨论非常激烈。当然,他们的“解决方案”是确保您至少使用ODP.NET 11.1.0.6.20或更高版本

    因为找不到解决方案,我们决定停止使用TransactionScope,自己安排回滚

    我发现TransactionScope和Oracle不能很好地混合,也许SQL Server处理得更好,但这不是我们的选择


    感谢阅读。

    machine.config中的默认事务超时是10分钟……这可能就是您超时的原因


    我知道这是一个老问题,但我会补充一点,因为我已经看到了很多

    你在用RAC吗?您是否与DBA合作,查看是否遇到锁定/阻塞。我已经使用System.Transactions与Oracle进行了多年,我唯一一次遇到类似问题是在使用RAC时,需要进行额外的配置

    发生的情况如下:您启动一个事务,并在事务期间打开连接(这很好)。但是,oracle服务未配置为用于分布式事务处理(这是服务上的一个简单复选框选项)。因此,其他连接开始跨越RAC集群中的多个实例,并且相关事务彼此不知道,从而导致.net进程自身阻塞


    这是一个简单的解决方案。您正在使用的oracle服务只需要启用DTP

    虽然这是一个老问题,但我希望这个答案能有所帮助。。。
    对于长时间运行的事务,这种情况尤其发生,因为基础IDbConnection在更长的时间内不会保持打开状态,并且会为transactionscope的某些部分创建新连接(连接池)。出于同样的原因,如果返回并使用相同的打开连接,则长事务可能会成功,否则它将失败。唯一的解决方案是控制连接创建并确保整个过程中只使用一个连接。

    首先解决主要问题:

  • 当超时设置为(除了我所做的内部工作之外)时,怎么可能发生超时异常 不知道)对于所有事务作用域都是相同的,并且有一个超时 定义为1天的值,其中异常发生在大约10天后 分钟