2016-05-23 113 views
1

我有一個ASP.Net WebAPI實例設置,使用MySQL數據庫進行存儲。我寫了一個ActionFilter,它處理在單個端點請求的生命週期中創建TransactionScopeTransactionScope與MySQL和分佈式事務

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從頂部周圍通過它,因爲這是一個簡單的例子,在實踐中通過服務之間的連接將需要大量重構(儘管如有必要,這可以完成)。我還了解到,最好在必要時打開/關閉連接(即儘可能少地打開連接)。該queryServiceupdateService打開/關閉DbConnection「通過using聲明S:

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

布拉德格蘭傑是正確的。它運作良好。我使用另一個MySQL連接而不是MySqlConnection。我想MySqlConnection不是由Oracle開發的。我確認https://www.devart.com/dotconnect/mysql/可以解決您的問題。請嘗試。 –

回答

1

System.Transactions.Transaction對象基於有多少單獨的「資源管理器」(例如數據庫)已經在事務中徵用來確定是否升級到分佈式事務。

它不會區分連接到不同物理數據庫(確實需要分佈式事務)的連接和具有相同連接字符串並連接到同一數據庫(可能不會)的多個MySqlConnection連接。 (要確定兩個單獨的「資源管理器」①代表相同的物理DB並且不是並行地使用,這將是非常困難的。)因此,當多個對象參與事務時,它將總是升級到分佈式事務。

發生這種情況時,您會遇到連接器/ NET不支持分佈式事務的MySQL bug #70587

解決方法是:

  1. 確保只有一個MySqlConnection對象任何TransactionScope內打開。
  2. 更改爲支持分佈式事務的單獨連接器。您可以使用MySqlConnector(NuGetGitHub)作爲Connector/NET的直接替代品。我聽說dotConnect for MySQL也支持他們(但還沒有嘗試過)。