【问题标题】:How to use nested TransactionScopes against an Azure SQL Database如何对 Azure SQL 数据库使用嵌套的 TransactionScope
【发布时间】:2015-08-13 15:39:17
【问题描述】:

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

我正在使用以下代码(.Net 4.5.1,我的代码一直是异步的,它是带有 EF6.1 的 ASP.Net MVC):

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 数据库支持。所以我有时会收到以下错误:

分布式事务管理器 (MSDTC) 的网络访问权限已 禁用。请在安全中启用 DTC 以进行网络访问 使用组件服务管理配置 MSDTC 工具。

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

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

所以我的问题是:

  • Azure SQL 数据库是否完全支持嵌套事务?
  • 为什么上述代码有时会升级到 MSDTC?

official documentation 说:

Microsoft Azure SQL 数据库不支持分布式 事务,即影响多个资源的事务。 有关详细信息,请参阅分布式事务 (ADO.NET)。

从 2.0 版本开始,应用程序事务可能是 自动提升为分布式事务。这适用于 使用 System.Data.SqlClient 类执行的应用程序 System.Transactions 上下文中的数据库操作 交易。

当您打开多个连接到 TransactionScope 中的不同服务器或数据库,或者当您 通过使用在 System.Transactions 对象中登记多个连接 EnlistTransaction 方法。交易促进也发生在 您打开到同一服务器的多个并发连接,并且 数据库在同一 TransactionScope 内或使用 EnlistTransaction 方法。

从 3.5 版本开始,交易将不会被提升,如果 并发连接的连接字符串正是 相同的。有关交易和避免交易的更多信息 推广,请参阅 System.Transactions 与 SQL Server 的集成 (ADO.NET)。

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

【问题讨论】:

  • TransactionScope 是为 implicit/automatic 事务(利用 MSDTC 服务)而不是 nested 事务而发明的。您似乎混淆了这些术语。升级到 DTC 可能正在发生,因为您有一些异步的东西(这意味着不同的线程,这可能意味着不同的连接)。我几乎看不出你为什么要把异步的东西放在这种(服务器?)代码中——超出了当前围绕“异步”的时尚:-)。更多关于升级的信息:stackoverflow.com/questions/1690892/…
  • @SimonMourier 我不确定我是否理解你的第一句话; TransactionScope 绝对支持嵌套事务(参见例如 stackoverflow.com/a/2742025/870604)。回滚根范围应该回滚整个操作。至于异步的东西,我使用它是出于可伸缩性/性能的原因。也就是说,即使这两个操作在两个不同的线程上执行,它们仍然使用相同的 DB 连接(使用了唯一的 DbContext 实例),这并没有改变这一事实。
  • 我从未说过 TS 不支持嵌套事务。我说你混淆了这两个概念。嵌套事务早在 DTC 存在之前就已经存在。您可以在没有 TS 的情况下进行嵌套事务,但您说的是嵌套 作用域。异步不会在这里带来任何可扩展性的好处,如果在幕后,您正在对一个独特的连接进行序列化(实际上可能更糟),无论如何我仍然对此表示怀疑。恕我直言,您应该显示完整的重现代码以避免疯狂猜测。
  • 分布式事务!=嵌套事务,首先你为什么需要它?如果嵌套事务已经在事务中,可以继续在同一个事务中操作。您可以轻松更改业务逻辑以加入现有事务而不是创建新事务,这就是环境事务的概念。
  • 我在打开阅读器并创建新的事务范围时看到此错误,如果您使用 .ToListAsync() 获取所有记录而不是枚举查询,此错误将消失。跨度>

标签: c# azure transactions async-await msdtc


【解决方案1】:

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

MultipleActiveResultSets=True;

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

【讨论】:

  • 我确信 MARS 已启用,但在仔细检查了我的连接字符串后,实际上并没有。除非 Azure DB 默认处于活动状态,否则这真的可能是我的问题
  • 我没有时间(在赏金结束之前)来完全测试这是否解决了我的问题,但这确实是我的连接字符串的问题(我确信 MARS 已启用,但实际上并非如此)。修复看起来很有希望,所以我给你赏金+赞成票,但稍后我会在能够正确测试所有内容后接受答案。谢谢!
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-08-27
      • 2021-07-16
      • 2021-12-19
      • 1970-01-01
      • 2020-12-22
      • 2021-08-24
      • 2015-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多