2016-05-23 5 views
1

MySQLデータベースをストレージに使用するASP.Net WebAPIインスタンスセットアップがあります。私は、TransactionScopeの作成を処理するActionFilterを、1つのエンドポイント要求の存続期間にわたって書いています。MySQLと分散トランザクションを使用するTransactionScope

public async Task<HttpResponseMessage> ExecuteActionFilterAsync(
    HttpActionContext actionContext, 
    CancellationToken cancellationToken, 
    Func<Task<HttpResponseMessage>> continuation) 
{ 
    var transactionScopeOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }; 
    using (var transaction = new TransactionScope(TransactionScopeOption.RequiresNew, transactionScopeOptions, TransactionScopeAsyncFlowOption.Enabled)) 
    { 
     var handledTask = await continuation(); 

     transaction.Complete(); 

     return handledTask; 
    } 
} 

は、その後、私は別のクエリを持っているエンドポイント全体/オープン/クローズ接続がDbConnection年代のautoenlist=true機能を使用することを命じます。例えば、エンドポイントは次のようになります。

public async Task<IHttpActionResult> CreateStuffAsync() 
{ 
    var query = this.queryService.RetrieveAsync(); 

    // logic to do stuff 

    var update = this.updateService.Update(query); 

    return this.Ok(); 
} 

私は(実際にはサービス間の接続を渡すと、大規模なリファクタリングを必要とするとき、単一DbConnectionを作成し、これは単純な例であるとして、上から周りにそれを渡すことはありません必要に応じてこれを行うことができます)。また、必要に応じて接続を開いたり閉じたりすることがより良いことを読んでいます(つまり、できるだけ短い時間開いたままにしておくこと)。 using文経由queryServiceupdateServiceオープン/クローズDbConnection年代:

var factory = DbProviderFactories.GetFactory("MySql.Data.MySqlClient"); 
using (var connection = factory.CreateConnection()) 
{ 
    connection.ConnectionString = "Data Source=localhost;Initial Catalog=MyDatabase;User ID=user;Password=password;Connect Timeout=300;AutoEnlist=true;"; 

    if (connection.State != ConnectionState.Open) 
    { 
     connection.Open(); 
    } 

    var result = await connection.QueryAsync(Sql).ConfigureAwait(false); 

    return result; 
} 

同じDbConnectionは、一般的に同じAPIエンドポイントの要求内の複数のクエリに使用されていない - しかし、同じ接続文字列です。

断続的に私は、接続を開こうとするとスローされた例外を見ています:

​​

接続のすべてが反対しているとき、分散トランザクションにトランザクションをエスカレートしようとしている理由を私は理解していません同じデータベース。または、TransactionScopeDbConnectionのインスタンスを誤解/誤解していますか?

+0

Bradly Graingerが正しいです。それはうまくいく。 MySqlConnectionの代わりに別のMySQL Connectionを使用します。MySqlConnectionはOracleによってもう開発されていないと思います。私はhttps://www.devart.com/dotconnect/mysql/で問題を解決できることを確認しました。試してみてください。 –

答えて

1

System.Transactions.Transactionオブジェクトは、いくつの別個の「リソースマネージャー」(例えば、データベース)がトランザクションに参加したかに基づいて、分散トランザクションにエスカレートするかどうかを決定します。

異なる物理データベース(分散トランザクションが必要)への接続と同じ接続文字列を持ち、同じデータベースに接続する複数の接続()は区別されません。 (2つの別々の「リソースマネージャー」が同じ物理的なDBを表し、2つが並行してではなく順番に使用されていると判断するのは非常に難しいでしょう)結果として、複数のオブジェクトがトランザクションに参加すると、常に分散トランザクションにエスカレートします。

この場合、MySQL bug #70587に実行され、分散トランザクションはConnector/NETでサポートされていません。

回避策は次のようになります。

  1. 一つだけMySqlConnectionオブジェクトがどのTransactionScope内で開かれていることを確認します。
  2. 分散トランザクションをサポートする別のコネクタに変更します。 MySqlConnector(NuGetGitHub)をConnector/NETのドロップイン置換として使用できます。私はdotConnect for MySQLもそれらをサポートしていると聞いたことがあるが(しかし、それを試していない)。
関連する問題