Подтвердить что ты не робот

Пул соединений SQL Server не обнаруживает закрытые соединения?

В течение многих лет я испытывал очень странные проблемы во всех моих веб-приложениях, которые подключаются к SQL-серверу.

Проблема заключается в том, что если что-то происходит с сервером базы данных (перезагрузка сервера или другая проблема), веб-приложение перестает работать с этой точки, даже если сервер базы данных жив и после этого.

Случается, что каждая операция ADO.NET(ExecuteNonQuery, CreateReader, BeginTransaction,...) завершается с InvalidOperationException: "Неверная операция. Соединение закрыто". Кажется, что вызов SqlConnection.Open() извлекает соединение из пула приложений, который... закрыт!

В соответствии с документацией пул подключений должен автоматически удалять отключенные соединения из пула соединений, но при закрытом соединении не считается "отключенным", поэтому вызов SqlConnection.Open() счастливо возвращает закрытое соединение, считая его открытым, не проверяя это.

Мое текущее обходное решение - проверить состояние соединения сразу после его открытия:

using (SqlConnection connection = new SqlConnection( connectionString ))
{
   connection.Open();

   if (connection.State != ConnectionState.Open)
   {
      SqlConnection.ClearAllPools();

      connection.Open();
   }

   // ...
}

Обходной путь, похоже, сейчас работает, но я не чувствую себя комфортно.

Итак, мои вопросы:

  • Почему SqlConnection.Open() возвращает закрытые соединения из пула соединений?
  • Является ли мой способ обхода действительным?
  • Есть ли лучший способ справиться с этим?
4b9b3361

Ответ 1

Недавно я сделал несколько подобных исследований в области объединения соединений по несколько иной причине, но, надеюсь, будет полезен. Я нашел:

  • даже когда вы закрываете соединение в коде, оно возвращается в пул без закрытия соединения, готового для дальнейшего использования.
  • если это соединение будет разорвано (например, перезагрузка SQL Server), когда соединение возвращается из пула для другого вызывающего абонента, и этот вызывающий абонент выполняет.Открытие на нем, не выполняет ошибку в это тот момент, когда сервер базы данных все еще работает. Это часть преимуществ производительности пула соединений, поскольку он фактически не возвращается к серверу базы данных для подключения.
  • когда вы на самом деле пытаетесь выполнить команду против соединения (например, ExecuteNonQuery), в данный момент он действительно генерирует исключение

Связи автоматически удаляются из пула, мои результаты заключаются в том, что это обычно происходило в течение нескольких минут после последнего использования. Таким образом, это может быть проблема синхронизации - и они очищаются, но не до того, как соединения снова будут повторно использованы.

Это были некоторые статьи, на которые я смотрел, в то время:
Sql Server Google Group
Использование пула соединений в ASP.NET

Edit:
Звучит странно, что плохая связь остается в пуле навсегда - вы уверены, что это определенно, а это не просто несколько плохих соединений? Если вы уверены, значит, похоже, что эти соединения не выпущены должным образом в вашем коде. Это еще одна очень хорошая статья, которую я прочитал некоторое время назад, в которой говорится (цитата):

Автоматически подключаемые соединения

Если объединенное соединение остается в "закрытое, но многоразовое" состояние для от 4 до 8 минут (интервал выбирается случайным образом) соединение механизм объединения закрывает физический соединение и отбрасывает объединенные подключение. То есть, если число остальных соединений больше чем минимальные соединения настроен для пула (по умолчанию 0). Обратите внимание, что соединение должно были закрыты приложением (и выпущен обратно в пул) до он может подвергаться автоматическому выпуск. Если вы не закрываете соединение в коде или сирот Объект подключения, объединение механизм ничего не сделает. Не здесь нет аргументов ConnectionString для измените значение тайм-аута.

Ответ 2

Мы видели ту же проблему из С++, используя ADO. Несколько лет назад, после работы с Microsoft Support, мы также реализовали аналогичную логику повтора в коде и reset пул соединений, который разрешил проблему.

Если есть лучшее обходное решение, люди в Microsoft Support либо не знали об этом, либо не делились (в то время в любом случае).