126

我正在尝试将async/集成await到我们的服务总线中。我SingleThreadSynchronizationContext基于此示例http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx实现了一个。

它工作正常,除了一件事:TransactionScope. 我等待里面的东西TransactionScope,它打破了TransactionScope.

TransactionScope似乎不适合async/ await,当然是因为它使用 . 将东西存储在线程中ThreadStaticAttribute。我得到这个例外:

“TransactionScope 嵌套不正确。”。

我试图TransactionScope在排队任务之前保存数据并在运行它之前恢复它,但它似乎并没有改变任何事情。而且TransactionScope代码是一团糟,所以很难理解那里发生了什么。

有没有办法让它工作?有什么替代方法TransactionScope吗?

4

4 回答 4

181

在 .NET Framework 4.5.1 中,有一组带有参数的新构造函数。TransactionScopeTransactionScopeAsyncFlowOption

根据 MSDN,它支持跨线程延续的事务流。

我的理解是,它是为了让您可以编写如下代码:

// transaction scope
using (var scope = new TransactionScope(... ,
  TransactionScopeAsyncFlowOption.Enabled))
{
  // connection
  using (var connection = new SqlConnection(_connectionString))
  {
    // open connection asynchronously
    await connection.OpenAsync();

    using (var command = connection.CreateCommand())
    {
      command.CommandText = ...;

      // run command asynchronously
      using (var dataReader = await command.ExecuteReaderAsync())
      {
        while (dataReader.Read())
        {
          ...
        }
      }
    }
  }
  scope.Complete();
}
于 2013-07-08T13:21:43.107 回答
14

回答有点晚了,但我在 MVC4 上遇到了同样的问题,我通过右键单击项目转到属性将我的项目从 4.5 更新到 4.5.1。选择应用程序选项卡将目标框架更改为 4.5.1 并使用事务,如下所示。

using (AccountServiceClient client = new AccountServiceClient())
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
}
于 2014-05-04T02:26:07.610 回答
6

您可以使用由Transaction.DependentClone()方法创建的DependentTransaction :

static void Main(string[] args)
{
  // ...

  for (int i = 0; i < 10; i++)
  {

    var dtx = Transaction.Current.DependentClone(
        DependentCloneOption.BlockCommitUntilComplete);

    tasks[i] = TestStuff(dtx);
  }

  //...
}


static async Task TestStuff(DependentTransaction dtx)
{
    using (var ts = new TransactionScope(dtx))
    {
        // do transactional stuff

        ts.Complete();
    }
    dtx.Complete();
}

使用 DependentTransaction 管理并发

http://adamprescott.net/2012/10/04/transactionscope-in​​-multi-threaded-applications/

于 2012-12-26T00:16:02.083 回答
0

如果有人仍然关注这个线程......

Microsoft.Data.SqlClient v3.0.1 看起来修复了 System.Transactions 在 .NET Framework 的 async/await 函数中的死锁问题!我用的是4.8。我使用显式分布式事务方法允许通过使用多个连接对单个 sql 服务器执行并行查询,但我确信 TransactionScope 的行为也更好。

创建一个 CommittableTransaction,创建任意数量的 SqlConnections,这些 SqlConnections 包含从父可提交表创建的 DependentTransaction,并行执行连接上的查询,在查询执行后完成依赖项,然后提交/回滚父可提交表。

我在 3 个不同的连接上使用 3 个并行异步插入到同一个数据库中对其进行了测试。当父可提交正在进行时,我使用了一个消息框来提示提交或回滚。当分布式事务处于活动状态时,表被锁定。我无法在 ssms 中选择它们。选择提交或回滚后,要么按预期工作。

上周使用 Microsoft.Data.SqlClient 3.0.0,这是不可能的,因为 .Commit() 方法会在异步函数中死锁。我什至用各种方法尝试过 BeginCommit/EndCommit。甚至在异步函数中招募依赖项时也会出现问题,但这也已修复。现在最简单的显式分布式事务方法适用于 async/await。

于 2021-09-28T00:13:51.757 回答