我们正在将SQL迁移到Azure。我们的DAL是基于实体框架4.x。我们希望使用Transient Fault Handling Block为SQL Azure添加重试逻辑。
总的来说,我们正在寻找最好的80/20规则(或者更多的是95/5,但你明白了) - 我们不打算花几周重构/重写代码(有很多它)。我很好地重新实现了我们的DAL框架,但不是所有编写和生成的代码都不再需要了,因为这已经只是针对少数情况。缓解>>>为我们消除这种边缘情况。
查看here at MSDN解释的可能选项,似乎案例#3 实施“最快”,但只是乍一看。稍微思考一下这个解决方案,让我感到震惊的是我们可能会遇到连接管理问题,因为这可以解决实体框架内置的管理连接的过程(即总是关闭它们)。在我看来,“解决方案”是确保我们实例化的100%的上下文使用块,但是使用我们的架构,这将是困难的。
所以我的问题是:从那个链接开始使用案例#3,是否存在连接问题,或者某些地方正在发生一些我不知道的魔法?
答案 0 :(得分:1)
我已经做了一些实验,结果证明这让我们回到过去习惯的旧“管理连接”状态,只是这次连接被抽象了我们一点而且我们必须现在“同样管理上下文”。
假设我们有以下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;
}
}
);
}
在这种情况下,我们强行打开Connection(这是此处的目标)。因此,Context在许多调用中保持开放。因此,我们必须告诉Context何时关闭连接。我们这样做的主要机制是在Context上调用Dispose方法。因此,如果我们只是允许垃圾收集来清理我们的上下文,那么我们允许连接保持悬空。
我通过切换Connection.Close()
块中try
的注释并对我们的数据库运行一系列单元测试来测试它。在不调用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会导致数据库被“限制”并最终脱机几个小时!)。
答案 1 :(得分:1)
这种方法的问题在于它只处理连接重试而不是命令重试。
如果您使用Entity Framework 6(目前处于alpha版本),那么对Azure SQL数据库的瞬态重试有一些新的内置支持(稍加配置):http://entityframework.codeplex.com/wikipage?title=Connection%20Resiliency%20Spec
我创建了一个库,允许您配置实体框架以使用故障处理块重试,而无需更改每个数据库调用 - 通常您只需要更改配置文件,可能需要更改一行或两行代码。
这允许您将它用于Entity Framework或Linq To Sql。