【问题标题】:Why is TransactionScope operation is not valid?为什么 TransactionScope 操作无效?
【发布时间】:2023-03-23 12:01:01
【问题描述】:

我有一个使用递归循环将项目插入 SQL Server 2005 数据库的例程。启动循环的第一个调用包含在使用 TransactionScope 的事务中。当我第一次调用 ProcessItem 时,myItem 数据按预期插入到数据库中。但是,当从 ProcessItemLinks 或 ProcessItemComments 调用 ProcessItem 时,我收到以下错误。

“该操作对交易状态无效”

我在 Windows 7 上使用 VS 2008 进行调试,并运行 MSDTC 以启用分布式事务。下面的代码不是我的生产代码,但设置完全相同。 AddItemToDatabase 是我无法修改的类上的一种方法,它使用标准的 ExecuteNonQuery() 创建一个连接,然后在完成后关闭并处理。

我查看了此处和互联网上的其他帖子,但仍然无法解决此问题。任何帮助将不胜感激。

using (TransactionScope processItem = new TransactionScope())
{
    foreach (Item myItem in itemsList)
    {
        ProcessItem(myItem);
    }   
    processItem.Complete();
}    
private void ProcessItem(Item myItem)
{
    AddItemToDatabase(myItem);
    ProcessItemLinks(myItem);
    ProcessItemComments(myItem);
}    
private void ProcessItemLinks(Item myItem)
{
    foreach (Item link in myItem.Links)
    {
        ProcessItem(link);
    }
}   
private void ProcessItemComments(Item myItem)
{
    foreach (Item comment in myItem.Comments)
    {
        ProcessItem(comment);
    }
}

这是堆栈跟踪的顶部。不幸的是,我无法将到目前为止的积累作为我无法披露的公司敏感信息来展示。

   at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
   at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
   at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

【问题讨论】:

  • 你能发布异常的堆栈跟踪吗?
  • 我添加了尽可能多的跟踪。希望够了!
  • 你能发布整个异常吗?发布 ex.ToString() 的输出,然后编辑任何敏感内容。我想知道是否有一两个 InnerException。
  • 嗨,Cragly,你解决了这个问题吗?我们面临同样的问题,但找不到任何关于如何解决它的提示。
  • 这是由于我的交易由于某种原因超时(建议摇晃)。我花了几天时间寻找这个问题,但无法深入了解它。最后,我 AddItemToDatabase(myItem) ,如果可行,则处理其余部分。如果没有,则将异常抛出堆栈。如果添加到数据库有效并且其他任何操作都失败了,我会尝试删除我添加到数据库中的项目。这不是一个理想的解决方案,但它是让它工作并让我登上头条的唯一方法:)。希望对您有所帮助。

标签: c# asp.net transactionscope


【解决方案1】:

分布式交易让我的头发过早地变白了:)

通常的嫌疑人

  1. 防火墙正在阻止 MSDTC
  2. 您的事务由于某种原因超时(尝试增加超时)
  3. 您在代码顶部的某处有另一个事务范围,它与当前事务混淆

使用 dtcping 等工具测试 MSDTC 是否工作正常

还可以先插入少量元素进行测试。您的代码似乎处于可以处理大量数据的递归循环中。也许您正在运行许多查询并且事务正在超时。

有时 System.Transactions.Transaction.Current 对发生的事情有一些线索。为这个全局变量添加一个监视

【讨论】:

  • 是的,我的头发开始掉了!将提供有关我如何处理上述建议的最新信息。
  • 超时让我抓到了好几次。很容易忘记分布式事务,尤其是在调试时。值得注意的是,默认只有 1 分钟。您可以通过将其添加到您的 app.config - <system.transactions><defaultSettings timeout="00:10:00"/></system.transactions> 或作为参数传递给 TransactionScope() 来增加它(例如到 10 分钟)
【解决方案2】:

默认最大超时为 10 分钟。但是,您可以在 machine.config 中覆盖它:

<configuration>
    <system.transactions>
        <machineSettings maxTimeout="00:00:30" />
    </system.transactions>
</configuration>

或者你可以在代码中使用反射来覆盖它:

    private static void OverrideTransactionScopeMaximumTimeout(TimeSpan timeOut)
    {

        // 1. create a object of the type specified by the fully qualified name

        Type oSystemType = typeof(global::System.Transactions.TransactionManager);

        System.Reflection.FieldInfo oCachedMaxTimeout = oSystemType.GetField("_cachedMaxTimeout", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);

        System.Reflection.FieldInfo oMaximumTimeout = oSystemType.GetField("_maximumTimeout", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);

        oCachedMaxTimeout.SetValue(null, true);

        oMaximumTimeout.SetValue(null, timeOut);

        // For testing to confirm value was changed

        // MessageBox.Show(string.Format(&quot;DEBUG SUCCESS!! &nbsp;Maximum Timeout for transactions is &#39;{0}&#39;&quot;, TransactionManager.MaximumTimeout.ToString()));

    }

更多信息:https://blogs.msdn.microsoft.com/ajit/2008/06/18/override-the-system-transactions-default-timeout-of-10-minutes-in-the-code/

【讨论】:

  • OverrideTransactionScopeMaximumTimeout 无需修改即可工作 machine.config ?真的吗?
  • 覆盖defaultSettings timeout ?
猜你喜欢
  • 2019-06-20
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 2014-07-20
  • 2015-09-05
  • 2013-02-23
  • 2012-04-03
  • 1970-01-01
相关资源
最近更新 更多