открыть / закрыть SqlConnection или оставить открытым?

Моя бизнес-логика реализована в простых статических классах со статическими методами. Каждый из этих методов открывает / закрывает соединение SQL при вызове:

public static void DoSomething()
{
    using (SqlConnection connection = new SqlConnection("..."))
    {
        connection.Open();

        // ...

        connection.Close();
    }
}

Но я думаю, что отказ от открытия и закрытия соединения экономит производительность. Я давно провел несколько тестов с классом OleDbConnection (не уверен насчет SqlConnection), и это определенно помогло работать вот так (насколько я помню):

//pass around the connection object into the method
public static void DoSomething(SqlConnection connection)
{
    bool openConn = (connection.State == ConnectionState.Open);
    if (!openConn)
    {
        connection.Open();
    }

    // ....

    if (openConn) 
    {
        connection.Close();
    }
}

Итак, вопрос - что выбрать: метод (а) или метод (б)? Я прочитал в другом вопросе stackoverflow, что пул соединений сохранил для меня производительность, мне вообще не нужно беспокоиться ...

PS. Это приложение ASP.NET - соединения существуют только во время веб-запроса. Не беспроигрышное приложение или сервис.


person Alex from Jitbit    schedule 14.12.2010    source источник
comment
Просто совет: используйте событие DbConnection.StateChange для отслеживания изменений в изменении состояния соединения (и может храниться локально) вместо непосредственной проверки свойства DbConnection.State. Это сэкономит вам затраты на производительность.   -  person decyclone    schedule 14.12.2010
comment
Одна деталь, которой не хватает, - это то, как этот метод является частью запроса страницы. Это единственный вызываемый метод или, как я предположил в своем ответе, один из многих методов, вызываемых при запросе страницы, он влияет на правильный ответ;)   -  person David Mårtensson    schedule 14.12.2010
comment
Дэвид - Вызывается МНОГО таких методов :)   -  person Alex from Jitbit    schedule 14.12.2010
comment
Случай A показывает отсутствие доверия к Dispose: см. stackoverflow.com/questions/1195829/ и пример в MSDN msdn.microsoft.com/en-us/library/   -  person user2864740    schedule 23.10.2016


Ответы (6)


Придерживайтесь варианта а.

Пул соединений - ваш друг.

person Adriaan Stander    schedule 14.12.2010
comment
ИМХО - он даже близко не должен. утилизация сделает это. - person Royi Namir; 08.01.2013
comment
@RoyiNamir Мне нравится призыв закрыть соединение. Специально для новичков и новичков в кодовой базе. Это более понятно и читабельно. - person edhedges; 25.07.2014
comment
@edhedges Использование как using, так и Close () в конечном итоге только вызовет путаницу у новичков. Они не собираются понимать цель использования using. Не используйте Close вместо того, чтобы научить их цели использования. Чтобы они могли учиться лучше и применять полученные знания к другим частям кода. - person Luis Perez; 09.10.2015
comment
Нужно ли / нужно ли вызывать Open ()? В настоящее время я использую его так: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); } - person ganders; 23.01.2020

Используйте Метод (а) каждый раз. Когда вы начнете масштабировать свое приложение, логика, которая имеет дело с состоянием, станет настоящей головной болью, если вы этого не сделаете.

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

person WeNeedAnswers    schedule 14.12.2010

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

Это становится более сложным, если вы сталкиваетесь с проблемами MSDTC, используя одну транзакцию вокруг кода, который использует несколько подключений, и в этом случае вам действительно нужно предоставить общий доступ к объекту подключения и закрыть его только после завершения транзакции.

Однако здесь вы делаете что-то вручную, поэтому вы можете изучить инструменты, которые управляют подключениями за вас, такие как DataSets, Linq to SQL, Entity Framework или NHibernate.

person Neil Barnwell    schedule 14.12.2010
comment
Вы не должны нормально открывать и закрывать соединение при каждом вызове метода, только один раз для каждого запроса страницы. По крайней мере, это то, что я узнал;) Открытие и закрытие требует времени. - person David Mårtensson; 14.12.2010
comment
@David Martensson - соединения фактически не открываются и не закрываются при вызове SqlConnection.Open. ASP.NET перерабатывает активные подключения из пула, когда строка подключения совпадает с ранее использованной строкой подключения. Накладные расходы, связанные с этим, несущественны, и, кроме того, попытка сделать это самостоятельно означает, что вы должны взять на себя все задачи управления по обеспечению активности соединения для каждого последующего использования, что добавляет сложности и накладных расходов. При использовании пула соединений рекомендуется открывать и закрывать его при каждом использовании. - person Jamie Treworgy; 14.12.2010
comment
При всем моем уважении, ответ "Всегда закрывать связи" не очень хорошо подходит к вопросу ... Я закрываю их. Вопрос в том, когда. - person Alex from Jitbit; 14.12.2010
comment
@David Martensson Один раз для каждой страницы упрощается. Вы правы в том, что если у вас есть несколько команд базы данных, которые нужно выполнить одну за другой, вы можете оставить соединение открытым, пока вы их выполняете. Если вы закроете и снова откроете, возникнут незначительные накладные расходы - соединение войдет в пул и будет извлечено из него через мгновение. - person Concrete Gannet; 31.03.2017
comment
@ Дэвид Мартенсон Но никогда не оставляйте соединение без дела. Если вы ждете действия пользователя или чего-то еще, закройте его. Если сомневаетесь, закройте. Вы открываете так поздно, как только можете, в надежде, что кто-то еще завершил соединение и объединил его. Затем вы отвечаете за услугу - закрывайте как можно раньше. - person Concrete Gannet; 31.03.2017
comment
@ConcreteGannet В вопросе конкретно указано, что это страница ASP.net, что означает, что во время рендеринга страницы вы никогда не получите никакого дополнительного ввода пользователя. Запрос состоит из получения или отправки на сервер с последующим ответом, и большинство запросов страниц выполняется менее чем за секунду. Если у вас такая большая нагрузка на сайт, что соединение сохраняется в течение 300-500 мс, я бы порекомендовал взглянуть на кеширование через memcached или redis, чтобы максимально исключить sql-запросы. - person David Mårtensson; 03.04.2017

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

Если вам сложно поверить в то, что объединение действительно будет быстрее, попробуйте следующее:

Добавьте где-нибудь следующее:

using System.Diagnostics;
public static class TestExtensions
{
    public static void TimedOpen(this SqlConnection conn)
    {
        Stopwatch sw = Stopwatch.StartNew();
        conn.Open();
        Console.WriteLine(sw.Elapsed);
    }
}

Теперь замените все вызовы Open() на TimedOpen() и запустите вашу программу. Теперь для каждой отдельной строки подключения, которая у вас есть, окно консоли (вывода) будет иметь одно открытое длительное время и несколько очень открытий.

Если вы хотите пометить их, вы можете добавить new StackTrace(true).GetFrame(1) + к вызову WriteLine.

person Chris Pfohl    schedule 05.04.2011

Есть различия между физическими и логическими соединениями. DbConnection - это своего рода логическое соединение, использующее базовое физическое соединение с Oracle. Закрытие / открытие DbConnection не влияет на вашу производительность, но делает ваш код чистым и стабильным - утечки соединения в этом случае невозможны.

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

Пул соединений освобождает вас от проверки состояния соединения - просто откройте, используйте и сразу же закройте.

person Tony Kh    schedule 14.12.2010
comment
Да, соединение не является соединением, то есть DbConnection не является физическим соединением. DbConnection - это класс .NET, который предоставляет методы и свойства для управления базовым физическим соединением. - person Concrete Gannet; 31.03.2017
comment
К сожалению, не сразу было очевидно, что все это было сделано неявно, но документация подробно описывает это. docs.microsoft.com/en- us / dotnet / framework / data / adonet / - person Austin Salgat; 28.04.2020

Обычно вы должны поддерживать одно соединение для каждой транзакции (без параллельных вычислений)

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

Даже если у ado.net есть свой пул подключений, стоимость диспетчерского подключения очень низкая, но подключение с повторным использованием является более лучшим выбором.

Почему бы не сохранить только одно соединение в приложении

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

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

person ShiningRush    schedule 25.07.2018