10

アプリケーションでデータベース アクセスを行う必要がある場合は、次のパターンを使用します。

  • クエリを実行するために、メソッドを呼び出すCreateOpenConnectionだけのメソッドを持つ静的ファクトリ クラスがあります。このメソッドは、クエリを実行する前に呼び出され、クエリが返された後に接続が破棄されます。new SqlConnection(myConnectionString)Open()
  • work.Commit()挿入/更新/削除の場合、次のような呼び出しで変更がバッチ処理されてデータベースに送信される Unit of Work パターンを使用します。

work.Commit:

using (var tranScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    using (var conn = DapperFactory.CreateOpenConnection())
    {
      var count = _changeTracker.CommitChanges(conn);

      tranScope.Complete();

      return count;
    }
}

これは、Web サービスの一部としての一般的な使用にはうまく機能するようですが、現在、これを Rebus と組み合わせて使用​​しようとすると、MSDTC の問題が発生します。

私が知る限り、Rebus (キュー内のメッセージを処理するとき) は新しいメッセージを作成するTransactionScopeので、メッセージの処理に失敗した場合はロールバックできます。さて、これ自体はこれまでのところうまくいきました。SqlConnectionRebus メッセージ ハンドラー内で問題なくnew を開くことができます (ただし、同じ Rebus 内で従来の Entity Framework クエリ手動の SqlConnections を使用TransactionScopeしても機能しませんが、現時点では問題とは考えていません)。しかし、昨日、次の質問をしました。

Rebus での特定のメッセージ タイプのシリアル処理

答えは、Rebus のサガ機能を使用することです。これを実装して、Rebus saga が新しい SQL Server データベースに永続化されるように構成してみました (個別の接続文字列を使用)。おそらく、その SQL Server の永続性を使用するSqlConnectionと、独自SqlConnection

分散トランザクション マネージャー (MSDTC) のネットワーク アクセスが無効になっています。コンポーネント サービス管理ツールを使用して、MSDTC のセキュリティ構成でネットワーク アクセスに対して DTC を有効にしてください。

MSDTC を有効にすることは、構成とパフォーマンスのオーバーヘッドに関して、私が非常に避けたいことです。そして、私は間違っているかもしれませんが、それは必要ではないようです.

ここで起こっていると私が推測するのは、Rebus がアンビエントTransactionScopeを作成し、SqlConnectionそれが作成した がそのスコープに参加するということです。また、独自のものを作成SqlConnectionしようとすると、そのアンビエント スコープにも参加しようとし、複数の接続が関係しているため、MSDTC に昇格されますが、失敗します。

これを修正する方法についてのアイデアはありますが、それが正しいことかどうかはわかりません。私がすることは次のとおりです。

  • アプリケーションの接続文字列に追加Enlist=falseして、アンビエント トランザクションに参加しないようにします。
  • メソッドを変更しCommitて、新しいものを作成しないようにしますTransactionScope(接続はこれ以上サブスクライブしないと言ったので、これ以上サブスクライブしません)が、conn.BeginTransaction.

そのようです:

var transaction = conn.BeginTransaction();

try
{
  var count = _changeTracker.CommitChanges(conn);
  transaction.Commit();
  return count;
}
catch
{
  transaction.Rollback();
  throw;
}
finally
{
  transaction.Dispose();
}

これが正しいアプローチであるかどうか、および考えられる欠点が何であるかはわかりません。

任意のヒント?

更新:明確にするために、work.Commit()問題を引き起こしているのはそれではありません。うまくいくと確信していますが、クエリが失敗するため、そこにたどり着くことはありません。

失敗するものの例:

public int? GetWarehouseID(int appID)
{
  var query = @"
select top 1 ID from OrganizationUnits o
where TypeID & 16 = 16 /* warehouse */";

  using (var conn = _dapper.OpenConnection())
  {
    var id = conn.Query<int?>(query).FirstOrDefault();

    return id;
  }
}

これは、 Rebus によって aTransactionScopeが作成されたとき、および Rebus によって aSqlConnectionが開かれた後に呼び出されます。my を開くSqlConnectionと、参加しようとしてクラッシュします

4

2 に答える 2

1

これは、使用している SQL Server のバージョンに大きく依存します。同様の問題に対処する別の SO の質問については、こちらを参照してください。

これは、SQL 2005 と SQL 2008 が同じ .xml 内で複数の接続を処理する方法が異なることに関係していますTransactionScope。つまり、SQL 2008 はTransactionScope、MSDTC にエスカレートすることなく、同じで複数の接続を開くことができます。

これはあなたが見ている問題でしょうか

この場合、SQL 2008 にアップグレードするか、MSDTC を有効にするかの 2 つのオプションしかないと思います。これらのオプションはどちらもおそらく大きな頭痛の種であることを理解しています。

于 2013-05-31T10:11:22.080 に答える