"Відкрити / закрити" SqlConnection чи тримати відкритим?


121

У мене бізнес-логіка реалізована в простих статичних класах зі статичними методами. Кожен з цих методів відкриває / закриває з'єднання SQL при виклику:

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

        // ...

        connection.Close();
    }
}

Але я думаю, що уникнення відкриття та закриття з'єднання економить продуктивність . Я зробив декілька тестів довгий час з класом OleDbConnection (не впевнений у SqlConnection), і це, безумовно, допомогло працювати так (наскільки я пам’ятаю):

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

    // ....

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

Отже, питання - чи слід вибрати метод (а) чи метод (б)? Я читав на іншому запитанні stackoverflow про те, що об’єднання з'єднань зберегло для мене продуктивність, мені не потрібно взагалі турбуватися ...

PS. Це програма ASP.NET - з'єднання існують лише під час веб-запиту. Не виграш-додаток чи послуга.


1
Порада. Використовуйте DbConnection.StateChangeподію для моніторингу змін у зміні стану з'єднання (і може зберігатися локально), а не перевіряти DbConnection.Stateвластивість безпосередньо. Це заощадить ваші витрати на продуктивність.
дециклон

1
Однією деталлю, якої не вистачає, є те, як цей метод є частиною запиту на сторінку. Це єдиний метод, який називається, чи це, як я припустив у своїй відповіді, один із багатьох методів, який називається у запиті сторінки, він впливає на те, який відповідь є правильним;)
Девід Мартенсон

Девід - МНОГО подібних методів називають :)
Олексій

1
Випадок A демонструє відсутність віри в розпорядження: див. Stackoverflow.com/questions/1195829/… та приклад на MSDN msdn.microsoft.com/en-us/library/…
користувач2864740

Відповіді:


82

Дотримуйтесь опції a .

Пул з'єднання - ваш друг.


37
ІМХО - він навіть не повинен робити близько. розпорядження зроблять це.
Рой Намір

2
@RoyiNamir Мені якось подобається дзвінок перервати з'єднання. Особливо для початківців та новачків до кодової бази. Він більш чіткий і читабельний.
краями

27
@edhedges Використання як "використання", так і Close () в кінцевому підсумку спричинить плутанину у новачків. Вони не збираються розуміти мету використання "використання". Не використовуйте "Закрити", а навчіть їх меті "використовувати". Щоб вони могли навчитися краще і застосувати те, що вони вивчають, до інших частин коду.
Луїс Перес

1
Чи потрібно / потрібно викликати "Open ()"? В даний час я використовую його так: використовую (var conn = GetConnection ()) {} public SqlConnection GetConnection () {повернути новий SqlConnection (_connectionString); }
подарунки

79

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

Об'єднання об'єднань робить те, що написано на жерсті. Просто подумайте, що відбувається, коли програма масштабує, і як важко було б керувати вручну, відкритим / закритим станом. Пул підключень виконує прекрасну роботу з автоматичного поводження з цим. Якщо ви турбуєтесь про продуктивність, подумайте про якийсь механізм кешування пам'яті, щоб нічого не було заблоковано.


33

Завжди закривайте з'єднання, як тільки ви закінчите з ними, тому вони, що лежать в основі підключення до бази даних, можуть повернутися в пул і бути доступними для інших абонентів. Об’єднання підключень досить добре оптимізоване, тому за це немає жодного помітного штрафу. Порада в основному така ж, як і для трансакцій - тримайте їх короткими та закритими, коли закінчите.

Це ускладнюється, якщо ви стикаєтеся з проблемами MSDTC, використовуючи одну транзакцію навколо коду, що використовує декілька з'єднань, і в цьому випадку вам потрібно ділитися об'єктом підключення і закривати його лише після того, як транзакція буде виконана.

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


Не слід нормально відкривати та закривати з'єднання під час кожного виклику методу, лише один раз для кожного запиту на сторінку. Ось що я навчився принаймні;) Відкриття та закриття коштує часу.
Девід Мертенсон

8
@David Martensson - з'єднання насправді не відкриваються та не закриваються, коли ви телефонуєте SqlConnection.Open. ASP.NET переробляє активні з'єднання з пулу, коли рядок з'єднання відповідає раніше використаній рядку з'єднання. Накладні витрати, які беруть участь у цьому, є несуттєвими, і, крім того, спроба "зробити це самостійно" означає, що ви повинні взяти на себе всі управлінські завдання забезпечення того, щоб з'єднання все ще було активним для кожного наступного використання, що додає складності та витрат. При об'єднанні з'єднань найкращою практикою є відкривання та закриття для кожного використання.
Джеймі Треворі

2
При всій моїй повазі відповідь "Завжди близько зв'язків" не дуже відповідає питанню ... Я їх закриваю. Питання - коли.
Олексій

@David Martensson "Один раз для кожної сторінки" спрощено. Ви маєте рацію, що якщо у вас є кілька команд бази даних для виконання одна за одною, ви можете тримати з'єднання відкритим під час їх виконання. Якщо ви закриєтесь і відновите її, буде незначна накладні витрати - з'єднання піде в басейн і мить з нього вийде.
Бетон Gannet

1
@David Martensson Але ніколи не підтримуйте простою. Якщо ви чекаєте дії від користувача або чогось іншого, закрийте його. Якщо сумніваєтесь, закрийте її. Ви відкриваєтеся як можна пізніше, сподіваючись, що хтось інший закінчив зв’язок і об'єднав його. Тоді ви повернете прихильність - закрийте, як тільки розумно можете.
Бетон Ганне

13

Відмова: Я знаю, що це давнє, але я знайшов простий спосіб продемонструвати цей факт, тому я вкладаю свої два центи.

Якщо у вас виникли труднощі вірити, що об'єднання дійсно пройде швидше, спробуйте:

Додайте десь таке:

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.


9

Є фізичні та логічні зв’язки. DbConnection - це своєрідний логічний зв'язок, і він використовує основне фізичне з'єднання з Oracle. Закриття / відкриття DbConnection не впливає на вашу ефективність, але робить ваш код чистим та стабільним - витоки підключення в цьому випадку неможливі.

Також слід пам’ятати про випадки, коли на db-сервері є обмеження для паралельних з'єднань - враховуючи це, потрібно зробити ваші з'єднання дуже короткими.

Пул підключення звільняє вас від перевірки стану з'єднання - просто відкрийте, використовуйте та негайно закривайте їх.


Так, з'єднання не є з'єднанням - тобто DbConnection не є фізичним з'єднанням. DbConnection - клас .NET, який надає методи та властивості для маніпулювання базовим фізичним з'єднанням.
Бетон Gannet

На жаль, не відразу було очевидно, що це робиться все неявно, але документація детально розроблена. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Остін Салгат

2

Зазвичай ви повинні зберігати одне з'єднання для кожної транзакції (не паралельних обчислень)

наприклад, коли користувач виконує зарядку, вашій програмі потрібно спочатку знайти баланс користувача та оновити його, вони повинні використовувати те саме з'єднання.

Навіть якщо у ado.net є пул підключень, вартість диспетчеризації з'єднання дуже низька, але кращий вибір - кращий вибір.

Чому б не зберегти лише одне з'єднання в додатку

Оскільки підключення блокується під час виконання якогось запиту чи команди, це означає, що ваша програма виконує лише одну db операцію в один і той же час, наскільки це низька продуктивність.

Ще однією проблемою є те, що у вашій програмі завжди буде з'єднання, навіть якщо ваш користувач просто відкриває його, але не виконує жодних операцій. Якщо багато користувачів відкриє вашу програму, db-сервер обійдеться в усі джерела підключення незабаром, поки ваші користувачі цього не зробили. що завгодно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.