Как принудительно физически закрыть SqlConnection при использовании пула соединений?
Я понимаю, что если я создаю экземпляр объекта SqlConnection, я действительно получаю соединение из пула соединений. Когда я вызываю Open(), он открывает соединение. Если я вызываю метод Close() или Dispose() для этого объекта SqlConnection, он возвращается в пул соединений.
Однако это не говорит мне, действительно ли оно закрыто или у меня все еще есть активное соединение с базой данных.
Как я могу заставить SqlConnection закрыться на сетевом уровне или хотя бы сказать, когда он закрывается?
Пример:
using(SqlConnection conn = new SqlConnection(DBConnString)) {
conn.Open();
SqlCommand cmd = conn.CreateCommand();
...
cmd.ExecuteReader(CommandBehavior.CloseConnection);
...
}
- Первый запуск: 300 мс
- Второй прогон: 100 мс
- Третий прогон: 100 мс
- После долгого ожидания (30 минут): 300 мс
Если соединение было TRULY закрыто, второй и третий прогоны также должны быть 300 мс. Но я знаю, что соединение не было действительно закрыто для этих запусков (я проверил монитор активности SQL Server). Не требуется дополнительных 200 мсек для аутентификации и т. Д.
Как заставить соединение действительно закрыться?
идеи
- Работает ли CommandBehavior.CloseConnection? (очевидно нет?)
- Работает ли настройка "Максимальный размер пула = 0" в строке подключения? (это было бы пирровым решением)
- Dispose() работает?
Рекомендации
- Статья о пуле подключений
- Вот еще один, который говорит нам, что Close() действительно не закрывает соединение.
- Статья о пулах за и против соединения
7 ответов
Ответ Мо Сиско (Позвони SqlConnection.ClearPool
) верно.
Иногда вам нужно соединение, чтобы действительно закрыть, а не вернуться в пул. Например, у меня есть модульный тест, который создает временную базу данных, строит схему, проверяет некоторые вещи, а затем удаляет чистую базу данных, если все тесты пройдены.
Когда пул соединений активен, команда сброса базы данных не выполняется, поскольку все еще существуют активные соединения. С точки зрения программиста, все SQLConnections закрыты, но, поскольку пул все еще держит один открытый, SQL Server не допустит удаления.
Лучшая документация о том, как обрабатываются пулы соединений, - это страница о пулах соединений SQL Server в MSDN. Никто не хочет полностью отключать пул соединений, потому что это улучшает производительность при многократных открытиях и закрытиях, но иногда вам нужно вызвать "принудительное закрытие" для SQLConnection, чтобы он отпустил базу данных.
Это делается с помощью ClearPool. Если вы позвоните SqlConnection.ClearPool(connection)
перед закрытием / утилизацией, когда вы действительно закроете / утилизируете, он действительно исчезнет.
Если вы не хотите использовать пул соединений, вы должны указать его в своем SqlConnection.ConnectionString
имущество. Например
"Data Source=MSSQL1;Database=AdventureWorks;Integrated Security=true;Pooling=false;"
Утилизация или закрытие SqlConnection
Объект просто собирается закрыть соединение и вернуть его в пул соединений.
Как правило, вы хотите, чтобы пул соединений выполнял свою работу - вы не хотите, чтобы соединение действительно закрывалось.
Почему конкретно вы хотите, чтобы соединение не возвращалось в пул?
Я вижу, что вы используете.net, но, как это выяснилось в запросе Google, позвольте мне дать ответ Java...
Используйте DataSource, который реализует Closeable(), и вызывайте close для DataSource. Хикари поддерживает Closeable.
CommandBehavior.CloseConnection
обычно не рекомендуется из-за этого самого факта - вы не можете быть уверены, что соединение будет закрыто. (Я попытаюсь найти некоторые конкретные доказательства этого, я говорю это из слабого отзыва).
Dispose()
самый верный путь, потому что он неявно вызывает Close()
,
using
Конструкция, продемонстрированная @Alex, является еще одним (дружественным к программисту) способом написания try-finally
построить с добавлением неявного избавления от объектов.
Изменить: (после редактирования на вопрос)
Ваше беспокойство по поводу фактического закрытия соединений кажется мне неоправданным. Соединение просто вернется в пул, чтобы его можно было легко использовать повторно, не выполняя всю инициализацию. Это не означает, что Соединение все еще активно подключено к БД.
Роберт ответ SqlConnection.ClearPool(TheSqlConn)
сделал именно то, что я хотел. Приятно знать, что пул МОЖЕТ взаимодействовать при необходимости.
Мой пример использования: мы испортили соединение и позволили ему вернуться в пул, как определить, что оно испорчено, и обновить его, чтобы у следующего пользователя не было проблем.
Решение было следующим: обнаружить, что мы только что испортили соединение, и полностью очистить его от пула, чтобы пул снова заполнился новыми соединениями.
Десять лет написания SqlClient.SqlConnection, и я даже не думал о взаимодействии с пулом до сегодняшнего дня.