2010-01-28 1 views
18

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

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

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

Согласно документации, пул соединений автоматически удалить разорваны соединения из пула соединений, но Apparantly замкнутое соединение не рассматривается как «разорваны», поэтому вызов SQLConnection.open() счастливо возвращает закрытое соединение, если оно открыто, не проверяя это.

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

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

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

     connection.Open(); 
    } 

    // ... 
} 

Это решение, кажется, работает на данный момент, но я не чувствую себя комфортно это делать.

Так что мои вопросы:

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

ответ

12

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

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

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

Это были некоторые статьи, которые я смотрел, в то время:
Sql Server Google Group
Using Connection Pooling in ASP.NET

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

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

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

+0

Я мог бы жить с «несколькими минутами», но при использовании соединения он явно генерирует исключение, но это «плохое» соединение остается доступным в пуле соединений навсегда. Он никогда не удаляется, хотя ADO.NET действительно генерирует исключение, потому что соединение было плохим. –

2

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

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

Смежные вопросы