我们在生产中遇到了一个重要应用程序的问题。作为短期修复,我们在代码中的许多地方增加了命令超时:
var cmd = new SqlCommand(szSQL, conn) {CommandTimeout = _cmdTimeout};
开发人员使用 500 秒(8 分钟以上)的初始默认值。在我们得到长期解决方案之前,这是我们的解决方案。我关心的是使用的秒数。8 分钟以上似乎很长(太长),我想知道使用这段时间还会引入哪些其他问题。尝试保持在 3-4 分钟以内会更好吗?还是8就好了?
我们在生产中遇到了一个重要应用程序的问题。作为短期修复,我们在代码中的许多地方增加了命令超时:
var cmd = new SqlCommand(szSQL, conn) {CommandTimeout = _cmdTimeout};
开发人员使用 500 秒(8 分钟以上)的初始默认值。在我们得到长期解决方案之前,这是我们的解决方案。我关心的是使用的秒数。8 分钟以上似乎很长(太长),我想知道使用这段时间还会引入哪些其他问题。尝试保持在 3-4 分钟以内会更好吗?还是8就好了?
我认为在必要时使用 8 分钟作为超时没有问题。AFAIK,SSMS 在运行查询时有无限超时!
但是,我会建议基于此提取的代码的稍微不同的方法:
private static bool IsRetryAfterException(SqlException aSqlExc)
{
if (aSqlExc != null)
{
// If anybody finds a better way than this, please update!
return aSqlExc.Message.Contains("The timeout period elapsed prior to completion of the operation or the server is not responding");
}
else
throw new ArgumentNullException("The parameter 'aSqlExc' cannot be null.");
}
private int CallExecuteNonQuery(SqlCommand aCmd)
{
for (int iRetry = 1; iRetry <= m_MaxTimeoutRetry; iRetry++)
try
{
return aCmd.ExecuteNonQuery();
}
catch (SqlException wSqlE)
{
if (iRetry == m_MaxTimeoutRetry || !IsRetryAfterException(wSqlE))
throw;
// otherwise, we double the timeout and retry
aCmd.CommandTimeout = 2 * aCmd.CommandTimeout;
// let SQL breathe a bit!
System.Threading.Thread.Sleep(aCmd.CommandTimeout * 10);
}
// This code cannot be reached but the compiler thinks otherwise
// this is because it cannot know that m_MaxTimeoutRetry is always >= 1 for the for-loop
throw new DataAccessException();
}
在我们的代码中,所有查询都是通过 CallExecuteNonQuery 方法调用的。这对您来说可能很难更改您的代码,但您可以使用 Lambda 表达式并轻松修改您现有的代码,以便它通过这种独特的方法而只需很少的更改......
所以问题是为什么要使用循环并重试?这是因为 SQL 死锁。我的经验是,最好让命令快速超时,比如 30 秒,如果超时,则通过将超时时间加倍并让 SQL 呼吸来重试,而不是默认情况下让所有查询都超时。
我希望这会有所帮助并且有意义。