Нет способа закрыть SqlConnection

Я знаю, что это старый вопрос. Тысячи утверждений в Google говорят Connection will be closed in Dispose(). Однако кто это действительно проверял?

Я обнаружил, что SqlConnection закрыть нельзя. У меня есть простая программа (с номером строки слева).

  class Program
  {
    static void Main(string[] args)
1   {
2        var connectionString = "Data Source=localhost;Initial Catalog=master;Integrated Security=SSPI;";
3        using (var conn = new SqlConnection(connectionString))
5        {
6            using (var cmd = new SqlCommand("create table #mytable(col1 int);", conn))
7            {
8                conn.Open();
9                cmd.ExecuteNonQuery();
10           }
11           conn.Close();
12           conn.Dispose();
13       }
14       GC.Collect();
15   }
  }

И у меня есть оператор T-SQL для проверки активного соединения

exec sp_who2

Я шагнул построчно с помощью отладчика, а тем временем проверил активное соединение с помощью sp_who2.

Все ожидают, что соединение должно быть закрыто в строке 11. Верно? Однако соединение находится в sleep после строки 11.

Хорошо, попробуйте удалить вручную на следующей строке. Но после строки 12 соединение все еще находится в sleep.

Хорошо, следующая строка - автоматическая утилизация. Но после строки 13 соединение все еще находится в sleep.

Хорошо, это может быть связано с GC. Поэтому я явно запустил GC.Collect(), чтобы попытаться собрать объект conn. Но после строки 14 соединение все еще находится в sleep.

Соединение фактически закрыто после строки 15. Это означает конец программы.

В приведенной выше программе создается временная таблица #mytable. Однако временная таблица будет удалена только в том случае, если соединение будет закрыто. Проблема, с которой мы столкнулись, это too many temp tables are in the database. (Да, я знаю, что временные таблицы следует удалять после использования.)

я тоже пытался

  1. используйте { }, чтобы создать новую область для переноса соединения. Результат тот же.

  2. создайте новый поток для подключения к серверу БД. Результат тоже тот же.

  3. используйте while(true) { Thread.Sleep(1000); GC.Collect(); } в конце метода Main. Результат тоже тот же.

Ни один из них выше не может закрыть SqlConnection. Как закрыть соединение?


person quofaye    schedule 23.04.2013    source источник


Ответы (1)


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

Чтобы отключить, добавьте аргумент Pooling=false в строку подключения:

var connection = new SqlConnection(
    @"Data Source=(local)\SQLEXPRESS;Initial Catalog=TEST;Integrated " +      
    "Security=SSPI;Pooling=false;");
person Kirk Woll    schedule 23.04.2013
comment
@quofaye, я рад, что это сработало для вас. Однако вам, вероятно, следует спросить себя, действительно ли вы хотите отключить пул соединений. Хотя, безусловно, приятно видеть, что ваши ресурсы отключаются, когда вы заканчиваете с ними работать, пулы соединений служат очень реальной цели. Как правило, получение новых соединений обходится довольно дорого, а необходимость выделения нового соединения без пула влечет за собой значительные совокупные накладные расходы, которые полностью устраняются пулом. - person Kirk Woll; 23.04.2013
comment
Спасибо за ваши комментарии. Да, это трудный выбор между включенным и выключенным пулом соединений. Однако я только что попытался использовать SqlConnection.ClearPool(conn), и соединение все еще активно. Кажется, нет надежного способа закрыть соединение. Pooling=false кажется единственным вариантом для моего случая. - person quofaye; 23.04.2013
comment
@quofaye, достаточно честно - если вам действительно нужно убедиться, что вы отключили соединение, когда закончите, вы, вероятно, правы, что это единственный вариант. - person Kirk Woll; 23.04.2013
comment
в большинстве случаев этого делать не нужно. если проблема связана с таблицей #temp, вы должны явно удалить временную таблицу, а не зависеть от sql. - person urlreader; 23.04.2013