Parallel.Invoke()、TransactionScope()およびSqlBulkCopy

c# multithreading sqlbulkcopy task-parallel-library transactionscope

質問

私は、トランザクションの内部で実行する必要があるParallel.Invoke()中に複数のメソッドを持っています。これらのメソッドはすべてSqlBulkCopyのインスタンスを呼び出します。ユースケースは "all-or-none"なので、1つのメソッドが失敗しても何もコミットされません。親トランザクションでComplete()メソッドを呼び出すと、 TransactionAbortedException ({"Transaction Timeout"})発生します。

これは親トランザクションです。

using (var ts = new TransactionScope())
     {
       var saveClone = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
       var saveErrorsClone = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
        var saveADClone = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
        var saveEnrollmentsClone = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
        Parallel.Invoke(_options, () =>
                    {
                        Save(data, saveClone);
                    },
                    () =>
                    {
                        SaveErrors(saveErrorsClone);
                    },
                    () =>
                    {
                        SaveEnrollments(data, saveEnrollmentsClone);
                    });
        ts.Complete();  
      }//***** GET THE EXCEPTION HERE *****

ここでは、 SqlBulkCopyを使用する依存トランザクションです(すべて同じ構造です)。私は親を渡して、子のTransactionScope割り当てます

private void Save(IDictionary<string, string> data, Transaction transaction)
        {
        var dTs = (DependentTransaction)transaction;

        if (transaction.TransactionInformation.Status != TransactionStatus.Aborted)
            {
               using (var ts = new TransactionScope(dTs))
                   {
                     _walmartData.Save(data);
                     Debug.WriteLine("Completed Processing XML - {0}", _stopWatch.Elapsed);
                      ts.Complete();
                    }
             }
        else
             {
                Debug.WriteLine("Save Not Executed - Transaction Aborted - {0}", _stopWatch.Elapsed);    
                dTs.Complete();
             }
        dTs.Complete();
}

EDIT (私のSqlBulkCopyメソッドを追加... トランザクションのparamのnullを通知

private void SqlBulkCopy(DataTable dt, SqlBulkCopyColumnMappingCollection mappings)
        {
            try
            {
                using (var sbc = new SqlBulkCopy(_conn, SqlBulkCopyOptions.TableLock, null))
                {
                    sbc.BatchSize = 100;
                    sbc.BulkCopyTimeout = 0;
                    sbc.DestinationTableName = dt.TableName;

                    foreach (SqlBulkCopyColumnMapping mapping in mappings)
                    {
                        sbc.ColumnMappings.Add(mapping);
                    }

                    sbc.WriteToServer(dt);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

エラーを修正することに加えて、私は代替案を公開しています。ありがとう。

受け入れられた回答

多くの苦労、研究、そして有効な答えの欠如の後、私は私の質問で説明したスタックでは不可能だと信じなければならない。私が考えると、痛みのポイントは、TransactionScopeとSqlBulkCopyの間にあると思います。私は、将来の視聴者のためにこの答えをここに入れています。誰かがそれを行うことができることを証明できるなら、私はこれを答えとして喜んで削除します。


人気のある回答

DependentCloneOption.BlockCommitUntilComplete選択してデッドロックのフォームを作成しています。

Parallel.Invokeは、すべての処理が完了するまで呼び出しスレッドをブロックします。 Parallel.Invokeによって完了しようとしているジョブは、(DependentCloneOptionのために)親トランザクションが完了するのを待つ間にすべてブロックされます。だから2人はお互いに待っている...デッドロック。親トランザクションは最終的にタイムアウトし、従属トランザクションをブロッキングから解放します。ブロッキングは、呼び出しスレッドのブロックを解除します。

DependentCloneOption.RollbackIfNotCompleteを使用できますか?



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ