我做了一些实验,结果证明这让我们回到了我们过去习惯的旧“管理连接”情况,只是这一次连接被抽象了一点,我们必须现在类似地“管理上下文”。
假设我们有以下OnContextCreated 实现:
private void OnContextCreated()
{
const int maxRetries = 4;
const int initialDelayInMilliseconds = 100;
const int maxDelayInMilliseconds = 5000;
const int deltaBackoffInMilliseconds = initialDelayInMilliseconds;
var policy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(maxRetries,
TimeSpan.FromMilliseconds(initialDelayInMilliseconds),
TimeSpan.FromMilliseconds(maxDelayInMilliseconds),
TimeSpan.FromMilliseconds(deltaBackoffInMilliseconds));
policy.ExecuteAction(() =>
{
try
{
Connection.Open();
var storeConnection = (SqlConnection) ((EntityConnection) Connection).StoreConnection;
new SqlCommand("declare @i int", storeConnection).ExecuteNonQuery();
//Connection.Close();
// throw new ApplicationException("Test only");
}
catch (Exception e)
{
Connection.Close();
Trace.TraceWarning("Attempted to open connection but failed: " + e.Message);
throw;
}
}
);
}
在这种情况下,我们强制打开连接(这是这里的目标)。因此,上下文在许多调用中保持打开状态。因此,我们必须告诉 Context 何时关闭连接。我们这样做的主要机制是在 Context 上调用 Dispose 方法。因此,如果我们只允许垃圾收集来清理我们的上下文,那么我们就允许连接保持打开状态。
我通过在try 块中切换Connection.Close() 上的cmets 并针对我们的数据库运行一堆单元测试来对此进行测试。在不调用Close 的情况下,我们跳到了~275-300 个活动连接(从SQL Server 的角度来看)。通过拨打Close,该数字徘徊在~12。然后,我用少量的单元测试复制了上下文,无论有没有using 块,并复制了相同的结果(不同的数字 - 我忘记了它们是什么)。
我使用以下查询来计算我的连接数:
SELECT s.session_id, s.login_name, e.connection_id,
s.last_request_end_time, s.cpu_time,
e.connect_time
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_exec_connections AS e
ON s.session_id = e.session_id
WHERE login_name='myuser'
ORDER BY s.login_name
结论:如果您使用此解决方法调用 Connection.Open() 以启用瞬态故障处理块,那么您必须为您使用的 所有 上下文使用 using 块,否则您将问题(使用 SQL Azure 会导致您的数据库被“限制”并最终离线数小时!)。