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.
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 –
@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
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. –