处理事务提交失败

注意

仅限 EF6.1 及更高版本 - 此页面中讨论的功能、API 等已引入 Entity Framework 6.1。 如果使用的是早期版本,则部分或全部信息不适用。

作为 6.1 的一部分,我们将为 EF 引入新的连接复原功能:当暂时性连接故障影响事务提交确认时,可以自动检测和恢复的功能。 此场景的完整详细信息在博客文章 SQL 数据库连接性和幂等性问题中进行了具体介绍。 总的来说,此场景为,在事务提交期间引发异常时,有两个可能的原因:

  1. 服务器上的事务提交失败
  2. 服务器上的事务提交成功,但连接问题阻止成功通知到达客户端

在第一种情况下,应用程序或用户可以重试操作,但当发生第二种情况时,应避免重试,应用程序可以自动恢复。 难点在于,如果不能检测到在提交期间报告异常的实际原因,应用程序将无法选择正确的操作过程。 通过 EF 6.1 中的新功能,EF 可以在事务提交成功的情况下仔细检查数据库,并以透明方式执行正确的操作过程。

使用功能

若要启用该功能,需要在 DbConfiguration 的构造函数中包含对 SetTransactionHandler 的调用。 如果不熟悉 DbConfiguration,请参阅基于代码的配置。 此功能可以与我们在 EF6 中引入的自动重试结合使用,这有助于处理由于暂时性故障而导致事务在服务器上提交失败的情况:

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;

public class MyConfiguration : DbConfiguration  
{
  public MyConfiguration()  
  {  
    SetTransactionHandler(SqlProviderServices.ProviderInvariantName, () => new CommitFailureHandler());  
    SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlAzureExecutionStrategy());  
  }  
}

如何跟踪事务

启用该功能后,EF 会自动向数据库添加一个名为“__Transactions”的新表。 每次 EF 创建事务时,都会在此表中插入一个新行,如果在提交期间发生事务失败,则会检查该行是否存在。

尽管 EF 可以最大程度地从表中删除不再需要的行,但如果应用程序过早退出,表可能会增长,因此在某些情况下可能需要手动清除表。

如何处理以前版本的提交失败

在 EF 6.1 之前,EF 产品中没有处理提交失败的机制。 可通过多种方式来处理 EF6 早期版本中出现的此类情况:

  • 选项 1 - 不执行任何操作

    事务提交期间连接失败的可能性较低,因此如果这种情况确实发生,应用程序失败也是可以接受的。

  • 选项 2 - 使用数据库重置状态

    1. 放弃当前 DbContext
    2. 创建新的 DbContext 并从数据库中还原应用程序的状态
    3. 通知用户上次操作可能没有成功完成
  • 选项 3 - 手动跟踪事务

    1. 将非跟踪表添加到用于跟踪事务状态的数据库。
    2. 在每个事务的开头向表中插入一行。
    3. 如果在提交期间连接失败,请检查数据库中是否存在相应的行。
      • 如果行存在,则正常继续,因为事务已成功提交
      • 如果该行不存在,则使用执行策略重试当前操作。
    4. 如果提交成功,则删除相应的行以避免表增长。

这篇博客文章包含了用于在 SQL Azure 上完成此操作的示例代码。