如何针对 Azure SQL 数据库使用嵌套的 TransactionScopes

How to use nested TransactionScopes against an Azure SQL Database

我目前正在尝试使用嵌套事务范围对 Azure SQL 数据库进行数据库访问。

我正在使用以下代码(.Net 4.5.1,我的代码一直是异步的,它是 ASP.Net MVC with 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);
}

一切都很好,除了有时 TransactionScope 升级到 MSDTC,这(显然)不受 Azure SQL 数据库的支持。所以我有时会收到以下错误:

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.

我可以将 Enlist=False 添加到我的连接字符串中,但它会破坏上面的代码,因为即使在没有 [=15] 的情况下处理外部 TransactionScope ,内部事务仍会插入到数据库中=].

我的目标是一个单一数据库,对我的整个HttpRequest使用一个单一Entity Framework上下文 , 始终使用相同的连接字符串.

所以我的问题是:

official documentation 说:

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

它没有回答我的任何问题。

MSDN:当在单个事务中关闭并重新打开连接时,可能会将事务提升为 DTC。因为Entity Framework是自动打开和关闭连接的,你应该考虑手动打开和关闭连接,避免事务提升。

要避免这种情况:How to Manually Open the Connection from the Object Context

尝试将此添加到您的连接字符串,它会打开 Multiple Active Result Sets。这应该可以解决 MSDTC 问题;尽管我对此不太确定。

MultipleActiveResultSets=True;

关于额外信息,nested transaction is not really nested transaction.

Azure SQL 数据库现在支持从 TransactionScope 将事务提升为分布式事务。现在可以在以前由于不支持 MSDTC 而无法使用的地方使用 TransactionScope。因此,您不一定需要像上一个回复中建议的那样控制连接的打开和关闭。参见:https://azure.microsoft.com/en-us/documentation/articles/sql-database-elastic-transactions-overview/

另请注意,Azure DB 目前仍不完全支持多个活动结果集。