SQL打开失败导致系统TransactionAbortedException(由于超时),直到应用程序池被回收

时间:2015-01-26 15:18:19

标签: sql-server entity-framework azure-sql-database

我们有一个托管在Azure中的辅助角色,并将SQL Azure用于其数据库。偶尔会出现SQL连接错误:System.Data.EntityException: The underlying provider failed on Open. ---> System.Data.SqlClient.SqlException: A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)

一旦发生此错误,以下所有创建连接/事务的尝试都将失败,并显示以下错误:System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout实际上使我们的整个服务无法使用(因为我们的所有服务都需要数据库访问)。

我们发现的唯一解决方案是手动回收应用程序池。显然,这会导致问题,因为每当发生这种情况时,我们的实例就会无法为请求提供服务,直到有人手动回收应用程序池。

显然,我们正在寻找另一种解决方案,要么完全解决问题,要么我们可以采用一种解决方法来自动化应用程序池循环(或者可以实现类似结果的东西)。

有一点需要注意,我们正在使用Entity Framework 4(旧项目,它按原样运行,我们还没有找到升级的理由)。因此,由于EF4将为每个查询或SaveChanges调用打开/关闭数据库连接,因此我们的代码会在使用ObjectContext.Connection.Open()创建事务时强制打开连接,以避免将事务提升为MSDTC如果同一事务中有多个查询或更新。在初始打开期间,异常发生。

对于我们使用TransactionScopeTransactionScopeOption.Required的{​​{1}}。

1 个答案:

答案 0 :(得分:0)

已找到解决方案!

问题是我们使用对象EFTransaction来包装TransactionScope以及ObjectContext,以便自动创建范围和打开连接。此代码在此类型的构造函数中找到:

this._transactionScope = new TransactionScope(transactionScopeOption, transactionOptions);
this.OpenConnection();

虽然类本身是IDisposable,但构造函数中发生异常。因此,永远不会分配对象的引用,并且永远不会调用Dispose()。因此,_transactionScope字段永远不会被处置,并且事务陷入困境,导致以下事务请求超时。

解决方案有两个方面:首先,在课堂上实现终结器。虽然最终确定执行的时间是未定义的,但仍然可以将待处理的事务处于不确定状态。至少在某些时候,对象将获得GC并且交易处理完毕,其他交易将恢复。

其次,如果打开失败,请在try / catch和this.OpenConnection()事务中包装Dispose()

this._transactionScope = new TransactionScope(transactionScopeOption, transactionOptions);
try
{
    this.OpenConnection();
}
catch
{
    this._transactionScope.Dispose();
    throw;
}

这处理异常情况并且不会留下任何待处理的“僵尸”事务。