0

我们在生产中遇到了一个重要应用程序的问题。作为短期修复,我们在代码中的许多地方增加了命令超时:

var cmd = new SqlCommand(szSQL, conn) {CommandTimeout = _cmdTimeout};

开发人员使用 500 秒(8 分钟以上)的初始默认值。在我们得到长期解决方案之前,这是我们的解决方案。我关心的是使用的秒数。8 分钟以上似乎很长(太长),我想知道使用这段时间还会引入哪些其他问题。尝试保持在 3-4 分钟以内会更好吗?还是8就好了?

4

1 回答 1

2

我认为在必要时使用 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 呼吸来重试,而不是默认情况下让所有查询都超时。

我希望这会有所帮助并且有意义。

于 2013-08-05T21:05:38.657 回答