2015-08-13 16 views
12

Attualmente sto cercando di utilizzare gli ambiti di transazione nidificati per l'accesso al DB su un database SQL di Azure.Come utilizzare TransactionScopes nidificati su un database SQL di Azure

Sto utilizzando il seguente codice (Net 4.5.1, il mio codice è asincrona fino in fondo, si tratta di ASP.Net MVC con 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); 
} 

Tutto va bene, ad eccezione a volte il TransactionScope si sta inoltrando a MSDTC che è (ovviamente) non supportato dal database SQL di Azure. Così a volte ricevo il seguente errore:

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.

potrei aggiungere Enlist=False alla mia stringa di connessione, ma sarebbe rompere il codice di cui sopra, in quanto l'operazione interna sarebbe ancora inserire al database anche se l'esterno TransactionScope è disposto senza Complete .

sto mira un singolo database , utilizzando un unico contesto Entity Framework per il mio intero HttpRequest, sempre con la stessa stringa di connessione.

Quindi le mie domande sono: transazioni

  • sono annidati supportati da Azure SQL Database a tutti?
  • perché il codice sopra riportato a volte aumenta a MSDTC?

Il official documentation dice:

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).

, che non risponde a nessuna delle mie domande.

+0

TransactionScope è stato inventato per la transazione * implicita/automatica * (sfruttando il servizio MSDTC), non per la transazione * nidificata *. Sembra che tu stia confondendo questi termini.Escalation to DTC sta probabilmente accadendo perché hai alcune cose asincrone (che significa thread diversi, che probabilmente significano connessioni diverse). Difficilmente vedo perché vuoi mettere cose asincrone in questo tipo di codice (server?) - al di là della moda attuale in giro "asincrono" :-). Maggiori informazioni sull'escalation qui: http://stackoverflow.com/questions/1690892/transactionscope-automatically-escalating-to-msdtc-on-some-machines –

+0

@SimonMourier Non sono sicuro di aver capito la tua prima frase; 'TransactionScope' supporta sicuramente le transazioni nidificate (vedi ad esempio http://stackoverflow.com/a/2742025/870604). Il rollback dell'ambito di root dovrebbe eseguire il rollback dell'intera operazione. Per quanto riguarda le cose asincrone, lo sto usando per motivi di scalabilità/prestazioni. Detto questo, non cambia il fatto che anche se le due operazioni vengono eseguite su due thread diversi, utilizzano ancora la stessa connessione DB (viene utilizzata un'istanza DbContext univoca). – ken2k

+0

Non ho mai detto che TS non supporta le transazioni nidificate. Ho detto che stai confondendo entrambe le nozioni. La transazione nidificata esisteva molto prima dell'esistenza di DTC. È possibile eseguire una transazione nidificata senza TS, ma si tratta di ambiti * annidati *. Async non porterà alcun vantaggio di scalabilità qui, se dietro la scena, stai serializzando su una connessione univoca (in realtà è probabilmente peggio), che comunque dubito comunque. IMHO dovresti mostrare un codice di riproduzione completo per evitare ipotesi selvagge. –

risposta

2

Prova ad aggiungere questo per la stringa di connessione, è accendere la Multiple Active Result Sets. Questo dovrebbe fermare il problema MSDTC; anche se non ne sono così sicuro.

MultipleActiveResultSets=True; 

Su informazioni extra, nested transaction is not really nested transaction.

+0

Ero convinto che MARS fosse abilitato, ma dopo aver controllato due volte la mia stringa di connessione in realtà non lo è. A meno che per Azure DB non sia attivo per impostazione predefinita, questo potrebbe essere il mio problema – ken2k

+0

Ho esaurito il tempo (prima della fine del bounty) per testare completamente se questo risolve il problema, ma questo era davvero un problema con la mia stringa di connessione (Ero sicuro che MARS era abilitato, ma in realtà non lo era). La correzione sembra promettente, quindi ti concedo il premio + un aumento, ma accetterò la risposta più tardi, dopo che sarò in grado di testare tutto correttamente. Grazie! – ken2k

0

MSDN: la promozione di una transazione in un DTC può verificarsi quando una connessione viene chiusa e riaperta in un'unica transazione. Poiché Entity Framework apre e chiude automaticamente la connessione, è consigliabile prendere in considerazione l'apertura e la chiusura manuale della connessione per evitare la promozione della transazione.

Per evitare questo scenario: How to Manually Open the Connection from the Object Context

0

Azure SQL Database ora supporta la promozione di una transazione per una transazione distribuita da TransactionScope. Ora è possibile utilizzare TransactionScope in cui in precedenza non era possibile poiché MSDTC non era supportato. Di conseguenza, non è necessario controllare la connessione aperta e chiusa come suggerito nella risposta precedente. Vedi: https://azure.microsoft.com/en-us/documentation/articles/sql-database-elastic-transactions-overview/.

Si noti inoltre che al momento il DB di Azure non supporta ancora più set di risultati attivi.

Problemi correlati