2012-03-13 11 views
5

アプリケーションでMSDTCエスカレーションを回避しようとしています。 SQL Server Express 2008 R2でLINQを使用していますが、後でフルバージョンを使用します。ネストされたTransactionScopeおよび/またはネストされた接続によってMSDTCエスカレーションが発生する

私は、必要に応じて接続を作成し、できるだけ早く廃棄するデータベースラッパークラスを作成しました。接続文字列は、すべての接続で同じままです。私は、PerformConnectionAction方法の内容を中心にその一つだけをロックをかける場合

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

次のように使用される

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); 
    } 
    } 
} 

:ここ

は私のクラスの非常にスリムダウンバージョンです一度に実行することができますが、すべてが機能しますが、顕著なパフォーマンス上のペナルティがあります。しかし、私はそれを削除すると、それはエスカレートします。

ラッパーを使用しているコードはTransactionScopeを使用しており、TransactionScopesのネストまたは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のない、そしてロックを導入することなく、うまく実行できるように、私はリファクタリングん/私のコードを書き直すか、あります?

おかげ

+0

使用しているSQL Serverのバージョンは? – Oded

+0

SQL Express 2008 R2は、後でフルバージョン – enashnash

+0

に置くことをお勧めします。ロックを追加すると、「TransactionScope」がスレッドバインドであり、ロックがスレッドの相互作用にのみ影響を及ぼしますが、順序は影響を受けないので、あなたのスレッドが非決定論的な振る舞いを引き起こさない限り、スレッド内での操作については、ロックがどのように変化するかを見ることができます。あなたがまだ答えに関心があるならば、スレッドに沿って何が起こっているのか、私たちにもっと教えてください。 –

答えて

1

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

スレッド静的変数に接続を保存し、トランザクション内のすべての作業が完了したときに閉じることができます。それから、すべてのスレッドはそれ自身の接続を持ちます。

ロジックにロックを追加すると、接続プールによって毎回同じ接続が返されるため、おそらく分散トランザクションは発生しません。

関連する問題