2015-08-13 9 views
12

Ich versuche derzeit verschachtelte Transaktionsbereiche für den DB-Zugriff auf eine Azure SQL-Datenbank zu verwenden.So verwenden Sie geschachtelte TransactionScopes für eine Azure SQL-Datenbank

Ich verwende den folgenden Code (.Net 4.5.1, meinen Code async ganzen Weg nach unten, dann ist es ASP.Net MVC mit EF6.1):

public async Task Test() 
{ 
    // In my actual code, the DbContext is injected within the constructor 
    // of my ASP.Net MVC Controller (thanks to IoC and dependency injection) 
    // The same DbContext instance is used for the whole HttpRequest 
    var context = new TestContext(); 

    using (var t1 = StartTransactionForAsync()) 
    { 
     using (var t2 = StartTransactionForAsync()) 
     { 
      context.Users.Add(new User { Name = Guid.NewGuid().ToString() }); 
      await context.SaveChangesAsync(); 

      t2.Complete(); 
     } 
     ... // Some more code here 
     t1.Complete(); 
    } 
} 

private static TransactionScope StartTransactionForAsync() 
{ 
    return new TransactionScope(
     TransactionScopeOption.Required, 
     new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, 
     TransactionScopeAsyncFlowOption.Enabled); 
} 

Alles in Ordnung, außer manchmal eskaliert die TransactionScope zu MSDTC, die (offensichtlich) nicht von Azure SQL-Datenbank unterstützt wird. So bekomme ich manchmal die folgende Fehlermeldung:

Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.

ich Enlist=False meiner Verbindungszeichenfolge hinzufügen könnte, aber es würde den Code oben brechen, da die innere Transaktion noch in die Datenbank einfügen würde, selbst wenn der äußere TransactionScope ohne Complete angeordnet ist, .

Ich bin eine einzige Datenbank Targeting, einen einzelnen Entity Framework Kontext für meinen ganzen HttpRequest, immer mit der gleichen Verbindungszeichenfolge verwenden.

Also meine Fragen sind:

  • sind verschachtelte Transaktionen an allen von Azure SQL-Datenbank unterstützt?
  • Warum eskaliert der obige Code manchmal zu MSDTC?

The official documentation sagt:

Microsoft Azure SQL Database does not support distributed transactions, which are transactions that affect several resources. For more information, see Distributed Transactions (ADO.NET).

Starting with the version 2.0, application transactions may be automatically promoted to distributed transactions. This applies to applications that use the System.Data.SqlClient class to perform database operations in the context of a System.Transactions transaction.

Transaction promotion occurs when you open multiple connections to different servers or databases within a TransactionScope, or when you enlist multiple connections in a System.Transactions object by using the EnlistTransaction method. Transaction promotion also occurs when you open multiple concurrent connections to the same server and database either within the same TransactionScope or by using the EnlistTransaction method.

Starting with the version 3.5, the transaction will not be promoted if the connection strings for the concurrent connections are exactly the same. For more information about transactions and avoiding transaction promotion, see System.Transactions Integration with SQL Server (ADO.NET).

, die keine meiner Fragen beantwortet.

+0

TransactionScope wurde für * implizite/automatische * Transaktion (unter Ausnutzung des MSDTC-Dienstes) erfunden, nicht für * verschachtelte * Transaktionen. Es scheint, dass Sie diese Begriffe verwirren.Eskalation zu DTC ist wahrscheinlich passiert, weil Sie etwas Async-Zeug haben (was verschiedene Threads bedeutet, was wahrscheinlich unterschiedliche Verbindungen bedeutet). Ich sehe kaum, warum du asynchrone Sachen in diese Art von (Server?) Code schreiben willst - jenseits der aktuellen Mode um "Async" :-). Mehr zur Eskalation hier: http://stackoverflow.com/questions/1690892/transactionscope-automatisch-escaling-to-msdtc-on-some-machines –

+0

@SimonMourier Ich bin mir nicht sicher, ob ich deinen ersten Satz verstehe; 'TransactionScope' unterstützt definitiv verschachtelte Transaktionen (siehe zum Beispiel http://stackoverflow.com/a/2742025/870604). Durch das Rollback des Root-Bereichs sollte die gesamte Operation zurückgesetzt werden. Was das Async betrifft, benutze ich es aus Gründen der Skalierbarkeit/Performance. Das ändert nichts an der Tatsache, dass selbst wenn die beiden Operationen auf zwei verschiedenen Threads ausgeführt werden, sie immer noch dieselbe DB-Verbindung verwenden (eine eindeutige DbContext-Instanz wird verwendet). – ken2k

+0

Ich habe nie gesagt, TS unterstützt verschachtelte Transaktionen nicht. Ich sagte, du verwirrst beide Begriffe. Verschachtelte Transaktionen existierten lange bevor DTC existierte. Sie können verschachtelte Transaktionen ohne TS durchführen, aber Sie sprechen von geschachtelten * Bereichen *. Async bringt hier keinen Skalierbarkeitsvorteil, wenn Sie hinter der Szene auf einer einzigen Verbindung serialisieren (es ist in der Tat wahrscheinlich schlimmer), was ich immer noch bezweifle. IMHO sollten Sie einen vollständigen Repro-Code zeigen, um wilde Vermutungen zu vermeiden. –

Antwort

2

versuchen, dies zu Verbindungszeichenfolge hinzufügen, schalten Sie ihn auf der Multiple Active Result Sets. Dies sollte das MSDTC-Problem stoppen; auch wenn ich mir da nicht so sicher bin.

MultipleActiveResultSets=True; 

auf zusätzliche Informationen, unterstützt nested transaction is not really nested transaction.

+0

Ich war davon überzeugt, MARS wurde aktiviert, aber nach der doppelten Überprüfung meiner Verbindungszeichenfolge ist es tatsächlich nicht. Außer für Azure DB ist es standardmäßig aktiv, das könnte wirklich mein Problem sein – ken2k

+0

Ich habe keine Zeit mehr (vor dem Ende der Bounty) zu testen, ob dies mein Problem behebt, aber das war wirklich ein Problem mit meiner Verbindungszeichenfolge (Ich war mir sicher MARS wurde aktiviert, aber es war tatsächlich nicht). Das Update sieht vielversprechend aus, also gebe ich Ihnen die Bounty + eine Verbesserung, aber ich werde die Antwort später akzeptieren, nachdem ich alles richtig testen kann. Vielen Dank! – ken2k

0

MSDN: Wenn eine Verbindung innerhalb einer einzelnen Transaktion geschlossen und erneut geöffnet wird, kann eine Übertragung zu einem Fehlercode (DTC) auftreten. Da das Entity Framework die Verbindung automatisch öffnet und schließt, sollten Sie in Betracht ziehen, die Verbindung manuell zu öffnen und zu schließen, um eine Transaktionsförderung zu vermeiden.

Um dieses Szenario zu vermeiden: How to Manually Open the Connection from the Object Context

0

Azure SQL-Datenbank nun auch die Förderung einer Transaktion zu einer verteilten Transaktion von Transaction. Dadurch ist es jetzt möglich, TransactionScope zu verwenden, wo dies zuvor nicht möglich war, da MSDTC nicht unterstützt wurde. Aus diesem Grund müssen Sie die Verbindung nicht unbedingt öffnen und schließen, wie in der vorherigen Antwort vorgeschlagen. Siehe: https://azure.microsoft.com/en-us/documentation/articles/sql-database-elastic-transactions-overview/.

Beachten Sie auch, dass Azure DB derzeit mehrere aktive Ergebnissätze noch nicht vollständig unterstützt.