TransactionScope和Oracle的问题

时间:2010-07-14 10:41:38

标签: c# oracle transactionscope

我们编写了一个C#3.5客户端,使用ODP.NET与Oracle数据库(11g)进行通信。

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

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

  1. 无法登记分布式交易
  2. 交易已中止。 (内部异常:交易超时)
  3. 我们目前使用一天超时进行交易(用于测试目的)。

    在UAT环境中运行所述进程会导致大约停止。 10分钟,上面有一个例外,所以没有办法接近超时值。

    这是第二个错误的堆栈跟踪片段:

    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)
    

    该过程尝试将项目保存到事务范围内的数据库,但堆栈跟踪显示构造函数被命中为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. 是否有必要为嵌套事务定义超时值,还是从环境事务中继承它?
    2. 当超时设置(可能除了我不知道的内部工作方式)与所有事务范围相同并且超时值定义为1天时,如何可能发生超时异常,其中大约在...之后发生异常10分钟?
    3. 是否可以阻止Oracle为连接字符串相同的事务创建分布式事务?
    4. 分布式事务的额外开销是否会导致事务中止的异常?
    5. 我更新了代码段,以便更好地反映情况。

      (顺便说一句:第二个嵌套事务是必要的,因为DAL还单独持有一些子项,如果存在的话,当然,如果出现任何问题,整个项目应该回滚,同时保留子项目)

      希望通过这一添加,可以更容易地阐明这个问题!

6 个答案:

答案 0 :(得分:5)

答案 1 :(得分:1)

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

答案 2 :(得分:0)

您是否有可能请出示一段代码?从你提到的内容我唯一能找到的东西与System.Transactions有关。讨论是here。当然,他们的“解决方案”是确保您至少使用ODP.NET 11.1.0.6.20或更高版本。

答案 3 :(得分:0)

我知道这是一个古老的问题,但我已经加入了它,因为我已经看到了这一点。

您使用的是RAC吗?您是否曾与DBA合作过以查看您是否遇到过锁定/阻止问题。我多年来一直使用System.Transactions和Oracle,而且我唯一有类似问题的时候就是我们使用RAC并需要完成其他配置。

这里发生了什么:你开始交易并在交易期间打开连接(这很好)。但是,oracle服务未配置为分布式事务处理(它是服务上的一个简单复选框选项)。因此,额外的连接开始跨越RAC集群中的多个实例,并且相关的事务彼此不知道导致.net进程阻塞自身。

这是一个简单的修复。您正在使用的oracle服务只需要启用DTP。

答案 4 :(得分:0)

虽然是一个老问题,我希望这个答案有助于...... 这对于长时间运行的事务尤其如此,因为基础IDbConnection不会保持打开更长的持续时间,并且会为transactioncope(连接池)的某些部分创建新连接。出于同样的原因,如果返回相同的打开连接并使用其他失败,则长事务可能会成功。对此的唯一解决方案是控制连接创建并确保始终只使用一个连接。

答案 5 :(得分:0)

首先解决主要问题:

  
      
  1. 超时设置是否可能发生超时异常(可能除了我做的内部工作外)   不知道所有事务范围相同并且超时   定义为1天的值,其中异常发生在大约1天之后。 10   分钟?
  2.   

TransactionManager.MaximumTimeout属性是您尝试通过范围设置的upper bound属性。在您的系统上,它设置为10 minutes,但根据documentation

  

可以在配置文件的MachineSettingsSection中设置此值。

至于其他问题:

  
      
  1. 是否有必要为嵌套事务定义超时值,还是从环境事务中继承它?
  2.   

启动交易的范围(即任何RequiresNew范围,任何最外Required范围以及Required范围Suppress将嵌套堆栈的范围设置为一级)将建立transaction timeout ,并且就我的the sources读取而言,此超时不受嵌套范围的影响< /强>

但是,参与现有事务的每个嵌套范围(即RequiredRequired范围内的任何RequiresNew范围都在堆栈的一个级别上除了上面提到的事务超时之外,还将建立自己的范围超时

事务超时范围超时在内部以不同方式实现,但如果这些超时中的任何一个命中,则将会滚动一个尚未成为Complete() d的事务回来。

顺便说一句,前面提到的TransactionManager.MaximumTimeout仅适用于交易超时范围超时没有上限。并不是真的很重要,因为无论如何最短的超时是最重要的。

  
      
  1. 是否可以阻止Oracle为连接字符串相同的事务创建分布式事务?
  2.   

只要你只有一个&#34;物理&#34;数据库连接在任何单个时间点打开,范围不会升级到DTC。如果我没记错的话,这可以与Oracle ODP.Net一起使用,尽管(this)似乎声称相反(可能它当时不适用于该版本?)。

您可能会也可能无法阻止并发连接even with nested scopes, and for different databases(只要它们位于同一台服务器上)。