我们有一个托管在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如果同一事务中有多个查询或更新。在初始打开期间,异常发生。
对于我们使用TransactionScope
和TransactionScopeOption.Required
的{{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;
}
这处理异常情况并且不会留下任何待处理的“僵尸”事务。