我做了一些实验,结果证明这让我们回到了我们过去习惯的旧的“管理连接”情况,只是这一次连接从我们身上抽象了一点,我们现在必须“管理上下文”类似。
假设我们有以下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 方法。因此,如果我们只允许垃圾收集来清理我们的上下文,那么我们就允许连接保持打开状态。
Connection.Close()
我通过切换块中的注释try
并针对我们的数据库运行一堆单元测试来测试这一点。在没有调用的情况Close
下,我们跳到了 ~275-300 个活动连接(从 SQL Server 的角度来看)。通过调用Close
,该数字徘徊在〜12。然后,我用少量的单元测试进行了复制,包括和不包括using
Context 块,并复制了相同的结果(不同的数字 - 我忘记了它们是什么)。
我正在使用以下查询来计算我的连接数:
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,将导致您的数据库被“限制”并最终离线数小时!)。