【问题标题】:Long running transactions with EF and SQL Server using Read Commited使用已提交读取与 EF 和 SQL Server 的长时间运行事务
【发布时间】:2014-12-13 11:50:15
【问题描述】:

我在 WPF 胖客户端应用程序上使用 EF6.1 和 SQL Server,默认情况下,我使用我实例化的每个 DbContext 打开一个事务(除非另有说明,我提交它并在每个 SaveChanges() 上重新打开它) .这些事务的隔离级别是 READ COMMITED (IsolationLevel.ReadCommited)。

默认情况下,我会在每个“主视图”上打开一个新上下文(因此是一个新事务)。该应用程序是一种假 MDI 应用程序,每个 MDI 视图都将使用自己的DbContext...“主视图”(每个 MDI 选项卡/窗口)可以包含其他辅助视图(想想用于特定数据输入的小模式窗口和类似的东西)将共享与在主视图中打开的相同的上下文(和事务)。我正在使用像UseCase -> Views -> ViewModels 这样的结构...通常“UseCase”会打开一个DbContext 并且可以生成多个视图,这些视图将共享它。这些次要视图通常调用SaveChanges() 而不提交事务,这就是为什么我希望将它们放在首位。

我在实验室服务器上对单个用户进行了一些性能测试,似乎在实例化上下文时打开事务或根本没有事务(其他而不是默认在SaveChanges() 上打开一个 EF)。

我不是 SQL Server 专家,所以我想知道在具有该隔离级别的 SQL Server 上打开许多长时间运行的事务是否有任何影响(当生产服务器上的多个用户使用该应用程序时) (我了解可能锁定读取的其他隔离级别的含义,但事实并非如此)。我在提交事务时手动处理并发错误。

我在这里做的事情是否正确,我应该坚持短期交易,还是只是偏好问题?

我一直在努力寻找答案,但没有找到任何确定的答案(有些人说长期交易不是一个好主意,但他们似乎没有解释原因)。

【问题讨论】:

  • 由于锁定和回滚情况下的待办事项量,事务应该尽可能短地打开。事务运行多长时间?
  • 为什么次要视图必须调用SaveChanges?在我看来,视图之间共享的上下文收集了所有更改,因此您可以在现在提交事务的那一刻进行一次SaveChanges 调用。
  • @GertArnold ,嗯,这些辅助视图接收一个上下文(可能是通过 DI 新建的,或者传入的),因此它们对正在编辑的实体进行更改,并在完成后调用 SaveChanges。此过程可能是更大更改的一部分(如果用户在主视图上取消,可能需要回滚)或者可能是全新上下文中的独立版本......视图没有意识到这一点,它只是调用 SaveChanges当它完成编辑时。我可以向视图传递一个参数,说明它是否应该保存更改,但我发现事务更优雅且更准确。
  • 好的,我明白了。但我不会说持久无知的应用程序代码中的事务管理比在封装数据库事务的工作单元(可能是上下文)中收集更改更优雅。我宁愿寻找在一个用例中涉及的视图之间共享工作单元的方法。一些 IoC 容器可以将组件的生命周期绑定到对象图中聚合根的生命周期(即主视图 + 子视图)。
  • 我当然过于简单化了,我正在传递我所谓的“ServiceTransaction”,其中包含一个 UoC(我的 dbcontext 实际上是 UoC),并且我使用服务进行访问。我可能只是跟踪我的更改或传递实体(而不是上下文),但我觉得概念上交易正是我所需要的......直到这个精确的主题进入我的脑海,我质疑是否这是正确的做法。

标签: c# sql-server entity-framework transactions


【解决方案1】:

有些人说长期交易不好 想法,但他们似乎没有解释原因

只有几个原因:

MS SQL 事务,取决于其隔离级别,可以获得记录(更通用)甚至元数据(更奇特)锁。事务存活的时间越长,它可以获得的锁就越多,因此死锁的概率也会增加。

此外,未提交的事务意味着服务器资源利用率。事务日志会增长,并且它的活动事务数据不能被截断,服务器必须记住所有事情,这些事情已经在事务中完成以提交或回滚。

默认情况下,我会使用我实例化的每个 DbContext 打开一个事务

应该有这样做的理由。我能想象的唯一原因是对数据库的非 EF 更改,这必须与 EF 更改一致。否则,你就是在做额外的工作,这至少是无用的,而且会浪费数据库服务器的资源。

【讨论】:

  • 它是否使用 Read Commited 隔离获得锁?此外,为什么长期事务会使用更多资源只是,因为它们比其他事务寿命更长?我真的在问这些问题,因为这在我的脑海中没有意义(正如我所说,我不是数据库专家)
  • 正如我解释的那样,使用事务的原因是能够在辅助视图上调用 SaveChanges(因此这些视图是自我管理的),而不会持久化对数据库的更改,直到在“主" 视图
  • @Jcl:SQL 服务器使用ReadCommitted 获取write 锁(我建议阅读此内容:technet.microsoft.com/en-us/library/…)。长寿命事务使用更多资源,因为通常,事务寿命越长,事务中执行的操作就越多。关于您的整体方法,我同意 Gert Arnold 的评论。
  • 这似乎是我错过的一个很好的链接......我会阅读它并尝试更好地理解它。谢谢,我将您的答案标记为已接受,因为它似乎是正确的。
猜你喜欢
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 2020-02-27
  • 2017-09-10
相关资源
最近更新 更多