【问题标题】:EF Transaction and AsyncEF 事务和异步
【发布时间】:2015-07-29 22:00:39
【问题描述】:

我在 ASP.NET MVC 中使用 EF 6。我在后台运行一些任务,所以我使用新的 EF 上下文和 Task 类来执行它。异步任务分为 3 个较小的任务,它们也应该在同一个数据库事务中运行异步。我不能使用 SaveAsync,因为我的代码是从同步和异步上下文中调用的。

Task.Run(() =>
            {
                try
                {
                    using (var transaction = dbContext.Database.BeginTransaction())
                    {
                        CalculateAmounts(id);

                        transaction.Commit();
                    }
                }
                finally
                {
                    dbContext.Dispose();
                }
            });

CalculateAmounts 方法创建了另外 3 个任务。我应该如何处理交易?

另一方面,当任务协同工作时,我遇到了一些错误,例如 DataReader 已经打开。我应该为每个任务创建一个上下文吗?在那种情况下,如何使它们都成为同一事务的一部分?

【问题讨论】:

  • Task.Run 在 ASP.NET 应用程序中几乎从来都不是一个好主意。您要么正在执行无法保证在 AppDomain 关闭之前完成的任务,要么只是增加了开销并降低了网站的可扩展性。
  • 如果您考虑长期运行的任务,我认为您的评论是正确的。我说的是不到 10 秒的任务。如果 AppDomain 关闭,在任何情况下都将是一场灾难(仅在一个线程或多个线程中执行)。

标签: c# entity-framework asynchronous


【解决方案1】:

恐怕你不能做你想做的事,原因如下:

异步任务分为 3 个较小的任务,它们也应该运行 异步但在同一个数据库事务中

单个数据库连接通常一次只能运行 1 个事务。这意味着您需要 3 个并发连接。

您仍然可以使用 TransactionScope 包装这 3 个连接的 distributed connection。问题是 TransactionScope 在任何不是它被启动的线程中都是不可见的。实际上,TS 是线程静态的,ADO.NET 会检查当前线程以确定它应该一起提交多个事务还是滚动他们都回来了。无论如何,它对你不起作用。

从 .NET 4.5.1 开始,有一个选项可以将 TransactionScopeAsyncFlowOption 传递给 TransactionScope,但它不会使其支持内部多线程。它只会支持async / await

TL;DR:最好并行地做所有事情,然后以串行方式提交所有事情。

【讨论】:

  • 您建议任务不保存任何内容,当所有任务完成后,我将保存到数据库并提交?问题是我正在运行一个 ASP.NET MVC 应用程序,并且任务让我在后台做一些事情时将页面返回给用户。至于 TransactionScope,Microsoft 建议从 EF6 开始使用 dbContext.Database.BeginTransaction。
  • 是的,这就是我的提议。
  • 是的,dbContext.Database.BeginTransaction 应该用于大多数情况。如果你想在一个全局分布式事务中提交多个内部事务,你仍然绑定到 TransactionScope。
  • “问题是我正在运行一个 ASP.NET MVC 应用程序,并且当我在后台执行一些操作时,任务让我将页面返回给用户。”
  • 我不能等待所有的任务。我做了一些同步的事情,在后台启动任务并返回带有中间结果的页面(在同步中计算的结果)。我希望能够在继续处理大笔交易的同时返回中间结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 2010-12-26
  • 2015-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-10
相关资源
最近更新 更多