5

アプリケーションで MSDTC エスカレーションを回避しようとしています。SQL Server Express 2008 R2 で LINQ を使用していますが、後でフル バージョンを使用する予定です。

必要に応じて接続を作成し、できるだけ迅速に破棄するデータベース ラッパー クラスを作成しました。接続文字列は、すべての接続で同じままです。

これは私のクラスの非常にスリム化されたバージョンです:

public class SqlServerDatabaseWrapper {

  public SqlServerDatabaseWrapper(string connectionString) {
    ConnectionString = connectionString; 
  }

  public string ConnectionString { get; private set; }

  private static IDbConnection GetOpenConnection() {
    var conn = new SqlConnection(ConnectionString);
    conn.Open();
    return conn;
  }

  // there is also a second method to return a value
  // there is PerformCommandAction for SqlCommand as well
  public void PerformDataContextAction<TContext>(Func<IDbConnection, TContext> creator, Action<TContext> action) where TContext : DataContext {
    PerformConnectionAction(conn => {
      using (var context = creator(conn))
        action(context);
    });
  }

  // there is also a second method to return a value
  public void PerformConnectionAction(Action<IDbConnection> action) {
    using (IDbConnection conn = GetOpenConnection(ConnectionString)) {
      action(conn);
    }
  }
}

次のように使用します。

var db = new SqlServerDatabaseWrapper(connectionString);
db.PerformDataContextAction(
  conn => new SomeDataContext(conn), 
  context => { /* do something */ }
);

PerformConnectionAction メソッドの内容をロックして、一度に 1 つしか実行できないようにすると、すべてが機能しますが、パフォーマンスが著しく低下します。ただし、削除するとエスカレートします。

ラッパーを使用しているコードは TransactionScope を使用しており、TransactionScope のネストおよび/または PerformDataContextAction または PerformConnectionAction の呼び出し (それぞれが同じ接続文字列で新しい接続を作成する) が存在する可能性があります。疑似コードで (これは異なるクラス/メソッドで発生する可能性があるため):

var db = new SqlServerDatabaseWrapper(connectionString)
using (TransactionScope tran = new TransactionScope()) {
  db.PerformDataContextAction( 
    /* ... */,
    context => {
      using (TransactionScope tran2 = new TransactionScope()) {
        db.PerformConnectionAction(conn => { /* some stuff */ });
        tran2.Complete();
      }
    }
  tran.Complete();
}

また、さまざまな時点で発生する可能性のある静的メンバーシップ メソッドが使用されていることにも注意してください。

また、接続文字列が次のようになっていることも付け加えておきます。

Data Source=.\SQLEXPRESS;Initial Catalog=db1;User Id=test1;Password=test1;MultipleActiveResultSets=true;Enlist=false;

問題は、MSDTC を使用せず、ロックを導入せずに、アプリケーションが適切に動作するようにコードをリファクタリング/リライトするにはどうすればよいかということです。

ありがとう

4

1 に答える 1

1

トランザクション スコープ内のデータベースへの接続を 1 つだけ使用していますか? トランザクション スコープ内で同じ接続文字列または異なる接続文字列を使用して 2 つの接続を作成すると、トランザクションが分散型にエスカレートされます。

接続をスレッドの静的変数に保存し、トランザクション内のすべての作業が完了したら閉じる/破棄することができます。次に、すべてのスレッドに独自の接続があります。

ロジックにロックを追加すると、接続プールが毎回同じ接続を返すため、おそらく分散トランザクションを取得できなくなります。

于 2012-05-02T11:15:08.503 に答える