14

再帰ループを使用してSQLServer2005データベースにアイテムを挿入するルーチンがあります。ループを開始する最初の呼び出しは、TransactionScopeを使用するトランザクション内に含まれています。最初にProcessItemを呼び出すと、myItemデータが期待どおりにデータベースに挿入されます。ただし、ProcessItemがProcessItemLinksまたはProcessItemCommentsのいずれかから呼び出されると、次のエラーが発生します。

「操作はトランザクションの状態に対して無効です」</p>

これをWindows7上のVS2008でデバッグして実行しており、分散トランザクションを有効にするためにMSDTCを実行しています。以下のコードは私の本番コードではありませんが、まったく同じように設定されています。PASSWORDToDatabaseは、変更できないクラスのメソッドであり、接続を作成し、完了すると閉じて破棄する標準の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()
4

2 に答える 2

26

分散トランザクションにより、私の髪は時期尚早に灰色になりました:)

ユージュアル・サスペクツ

  1. ファイアウォールがMSDTCをブロックしています
  2. 何らかの理由でトランザクションがタイムアウトしています(タイムアウトを増やしてみてください)
  3. 現在のトランザクションを混乱させているコードの上部に別のトランザクションスコープがあります

dtcpingなどのツールを使用して、MSDTCが正常に機能しているかどうかをテストします

また、最初に少数の要素を挿入してテストします。コードは、大量のデータを処理できる再帰ループにあるようです。たぶん、あなたは多くのクエリを実行していて、トランザクションがタイムアウトしています。

System.Transactions.Transaction.Currentには、何が起こったのかについての手がかりがあります。このグローバル変数に対するウォッチを追加します

于 2010-03-23T19:47:10.937 に答える
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/

于 2016-10-18T15:33:29.303 に答える