Класс .NET SqlConnection, логика пула соединений и переподключения - PullRequest
8 голосов
/ 29 июня 2009

У нас есть некоторый клиентский код, который использует класс SqlConnection в .NET для связи с базой данных SQLServer. Периодически происходит сбой с этой ошибкой:

«ExecuteReader требует открытого и доступного соединения. Текущее состояние соединения закрыто»

«Временное» решение состоит в перезагрузке процесса, после которого все работает - однако это явно неудовлетворительно.

Код хранит кэш экземпляров SqlConnection, по одному для каждой базы данных.

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

Мой первый вопрос: неэффективно ли повторно подключать и отключать объекты SqlConnection, или базовая библиотека выполняет пул соединений от нашего имени?

// Is this bad/inefficient?
for(many-times)
{
    using(SQLConnection conn = new SQLConnection(connectionString))
    {
        // do stuff with conn
    }
}

Поскольку наш код не делает вышеописанное, вероятной причиной проблемы является то, что во время «жизни» соединения что-то происходит с базовой базой данных SQLServer, что приводит к закрытию соединения. ...

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

  • База данных переведена в автономный режим и снова подключена к сети, но клиентский процесс не имел открытых транзакций, пока это происходило
  • База данных была "отключена", затем "повторно подключена"

Я заметил, что в SqlConnection есть свойство "State" ... есть ли подходящий способ сделать запрос?

Наконец, у меня есть тестовый экземпляр SQLServer, настроенный с полными правами доступа: как мне воспроизвести точную ошибку: «ExecuteReader требует открытого и доступного соединения. Текущее состояние соединения закрыто» *

Ответы [ 3 ]

20 голосов
/ 29 июня 2009

Нет, не менее неэффективно создавать множество SqlConnection объектов и закрывать каждый из них, когда вы закончите. Это именно то, что нужно сделать. Пусть пул соединений .NET Framework сделает свое дело - не пытайтесь делать это самостоятельно. Вам не нужно делать ничего конкретного, чтобы включить пул соединений (хотя вы можете отключить его, установив Pooling=false в строке подключения).

Есть много вещей, которые могут пойти не так, если вы попытаетесь кэшировать соединение самостоятельно. Просто скажи нет:)

2 голосов
/ 29 июня 2009

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

Стоимость создания нового соединения «с нуля» значительна, потому что для аутентификации требуется несколько циклов между клиентом и сервером (в зависимости от метода аутентификации и настроек SSL это может быть 1 раунд в лучшем случае против 10 в худшем ).

И чтобы ответить на ваш вопрос, соединение вызывает событие OnStateChange , когда изменяется их состояние, но вам не следует беспокоиться об этом, если вы используете пул.

1 голос
/ 08 января 2012

По моему недавнему опыту, если вы используете этот код:

using(SQLConnection conn = new SQLConnection(connectionString))
{
    // do stuff with conn
}

имеют ошибку и не закрывают соединение явно, оно не будет закрыто или возвращено в пул. Так что используйте catch или finally блок, чтобы закрыть соединение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...