SqlConnection'ı "aç / kapat" mı yoksa açık tut?


122

İş mantığımı statik yöntemlerle basit statik sınıflarda uyguladım. Bu yöntemlerin her biri çağrıldığında SQL bağlantısını açar / kapatır:

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

        // ...

        connection.Close();
    }
}

Ancak bir bağlantıyı açıp kapatmaktan kaçınmanın performanstan tasarruf ettiğini düşünüyorum . Çok uzun zaman önce OleDbConnection sınıfıyla (SqlConnection hakkında emin değilim) bazı testler yaptım ve kesinlikle böyle çalışmasına yardımcı oldu (hatırladığım kadarıyla):

//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();
    }
}

Öyleyse soru şu - (a) yöntemini mi yoksa (b) yöntemini mi seçmeliyim? Başka bir yığın aşımı sorusunda, bağlantı havuzlamasının performansı kaydettiğini okudum, hiç uğraşmam gerekmiyor ...

PS. Bu bir ASP.NET uygulamasıdır - bağlantılar yalnızca bir web isteği sırasında mevcuttur. Kazanma uygulaması veya hizmet değil.


1
Sadece bir tavsiye: Özelliği doğrudan DbConnection.StateChangekontrol etmek yerine bağlantının durum değişikliğindeki (ve yerel olarak depolanabilir) değişiklikleri izlemek için olayı kullanın DbConnection.State. Size performans maliyetinden tasarruf sağlayacaktır.
Decyclone

1
Eksik olan ayrıntılardan biri, bu yöntemin nasıl bir sayfa isteğinin parçası olduğudur. Bu denilen tek yöntem mi, yoksa yanıtımda varsaydığım gibi, bir sayfa isteğinde çağrılan birçok yöntemden biri, hangi cevabın doğru olduğunu etkiler;)
David Mårtensson

David - Bunun gibi BİRÇOK yöntem çağrılıyor :)
Alex

1
Durum A,
Dispose'a

Yanıtlar:


82

A seçeneğine sadık kalın .

Bağlantı havuzu, arkadaşınızdır.


37
IMHO - yakın bile yapmamalı. elden çıkarmak bunu yapacak.
Royi Namir

2
@RoyiNamir Bağlantıyı kapatmak için yapılan aramayı beğendim. Özellikle kod tabanına yeni başlayanlar ve yeni başlayanlar için. Daha açık ve okunaklı.
kenarlar

27
@edhedges Hem "kullanarak" hem de Close () kullanmak, sonuçta yalnızca yeni gelenler için kafa karışıklığına neden olacaktır. "Kullanmanın" amacını anlamayacaklar. "Kapat" ı kullanmayın, bunun yerine onlara "kullanmanın" amacını öğretin. Böylece daha iyi öğrenebilirler ve öğrendiklerini kodun diğer bölümlerine uygulayabilirler.
Luis Perez

1
"Open ()" çağrılması gerekiyor mu / gerekli mi? Şu anda bunu şu şekilde kullanıyorum: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
ganders

79

Her seferinde Yöntem (a) 'yı kullanın. Uygulamanızı ölçeklendirmeye başladığınızda, durumla ilgilenen mantık, yapmazsanız gerçek bir acıya dönüşecektir.

Bağlantı havuzu, teneke üzerinde söylediği şeyi yapar. Sadece uygulama ölçeklendiğinde ne olacağını ve bağlantı açık / kapalı durumunu manuel olarak yönetmenin ne kadar zor olacağını bir düşünün. Bağlantı havuzu, bunu otomatik olarak ele alma konusunda iyi bir iş çıkarır. Performans konusunda endişeliyseniz, hiçbir şeyin engellenmemesi için bir tür önbellek mekanizması düşünün.


34

Bağlantıları her zaman onlarla işiniz biter bitmez kapatın, böylece temeldeki veritabanı bağlantısı havuza geri dönebilir ve diğer arayanlar tarafından kullanılabilir. Bağlantı havuzlaması oldukça iyi optimize edilmiştir, bu nedenle bunu yapmanın dikkate değer bir cezası yoktur. Tavsiye, temelde işlemlerle aynıdır - işiniz bittiğinde bunları kısa ve yakın tutun.

Birden çok bağlantı kullanan kod etrafında tek bir işlem kullanarak MSDTC sorunlarıyla karşılaşıyorsanız daha karmaşık hale gelir, bu durumda bağlantı nesnesini gerçekten paylaşmanız ve işlem tamamlandıktan sonra kapatmanız gerekir.

Ancak burada işleri elle yapıyorsanız, DataSets, Linq to SQL, Entity Framework veya NHibernate gibi sizin için bağlantıları yöneten araçları araştırmak isteyebilirsiniz.


Normalde her yöntem çağrısında bir bağlantı açıp kapatmamalısınız, her sayfa isteği için yalnızca bir kez. En azından öğrendiklerim bu;) Açılış ve kapanış zamana mal oluyor.
David Mårtensson

8
@David Martensson - SqlConnection.Open'ı aradığınızda bağlantılar aslında açılıp kapanmaz. ASP.NET, bağlantı dizesi önceden kullanılan bir bağlantı dizesiyle eşleştiğinde havuzdaki etkin bağlantıları geri dönüştürür. Bununla ilgili ek yük önemsizdir ve ek olarak, "kendi başınıza yapmaya" çalışmak, bağlantının sonraki her kullanım için hala aktif olmasını sağlamaya yönelik tüm yönetim görevlerini üstlenmeniz gerektiği anlamına gelir, bu da karmaşıklığı ve ek yükü artırır. Bağlantı havuzu oluşturmada en iyi uygulama, her kullanım için açıp kapatmaktır.
Jamie Treworgy

2
Tüm saygımla, "Her zaman yakın bağlantılar" cevabı soruya pek uymuyor ... Onları kapatıyorum. Soru şu - ne zaman.
Alex

@David Martensson "Her sayfa için bir kez" çok basitleştirilmiştir. Birbiri ardına yürütmek için birkaç veritabanı komutunuz varsa, bunları yürütürken bağlantıyı açık tutabileceğiniz konusunda haklısınız. Kapatıp yeniden açarsanız küçük bir ek yük olacaktır - bağlantı havuza girecek ve bir dakika sonra ondan alınacaktır.
Concrete Gannet

1
@David Martensson Ama asla boşta bir bağlantı bırakmayın. Kullanıcının bir eylemi veya başka bir şey bekliyorsanız, kapatın. Şüpheniz varsa kapatın. Bir başkasının bir bağlantıyı bitirmesi ve bir araya getirmesi umuduyla olabildiğince geç açarsınız. Sonra iyiliğe geri dönersiniz - makul bir şekilde yapabildiğiniz kadar erken kapatın.
Concrete Gannet

13

Feragatname: Bunun eski olduğunu biliyorum, ancak bu gerçeği göstermenin kolay bir yolunu buldum, bu yüzden iki sent değerimi koyuyorum.

Havuzlamanın gerçekten daha hızlı olacağına inanmakta güçlük çekiyorsanız, şunu deneyin:

Aşağıdakileri bir yere ekleyin:

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

Şimdi tüm çağrıları Open()ile değiştirin TimedOpen()ve programınızı çalıştırın. Şimdi, sahip olduğunuz her farklı bağlantı dizesi için, konsol (çıkış) penceresi tek bir uzun süre açık olacak ve bir grup çok hızlı açılacaktır.

Onları etiketlemek istiyorsanız new StackTrace(true).GetFrame(1) +, çağrıya ekleyebilirsiniz WriteLine.


9

Fiziksel ve mantıksal bağlantılar arasında farklar vardır. DbConnection bir tür mantıksal bağlantıdır ve Oracle ile temelde yatan fiziksel bağlantıyı kullanır. DbConnection'ı kapatmak / açmak performansınızı etkilemez, ancak kodunuzu temiz ve kararlı hale getirir - bu durumda bağlantı sızıntıları imkansızdır.

Ayrıca, db sunucusunda paralel bağlantılar için sınırlamalar olduğu durumları da hatırlamalısınız - bunu hesaba katarak bağlantılarınızı çok kısa yapmanız gerekir.

Bağlantı havuzu sizi bağlantı durumu kontrolünden kurtarır - sadece açın, kullanın ve hemen kapatın.


Evet, bağlantı bağlantı değildir - yani DbConnection fiziksel bağlantı değildir. DbConnection, temeldeki fiziksel bağlantıyı işlemek için yöntemler ve özellikler sağlayan bir .NET sınıfıdır.
Concrete Gannet

Maalesef, bunun dolaylı olarak yapıldığı hemen belli değildi, ancak dokümantasyon bunu ayrıntılı olarak açıklıyor. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat

2

Normalde her işlem için bir bağlantı tutmalısınız (paralel hesaplama yok)

Örneğin, kullanıcı ücretlendirme işlemini gerçekleştirdiğinde, uygulamanızın önce kullanıcı bakiyesini bulması ve güncellemesi gerekir, aynı bağlantıyı kullanmaları gerekir.

Ado.net kendi bağlantı havuzuna sahip olsa bile, bağlantı gönderme maliyeti çok düşüktür, ancak bağlantıyı yeniden kullanmak daha iyi bir seçimdir.

Neden uygulamada yalnızca bir bağlantı tutmuyorsunuz?

Bir sorgu veya komut yürüttüğünüzde bağlantı engellendiği için, bu, uygulamanızın aynı anda yalnızca bir db işlemi yaptığı anlamına gelir, ne kadar düşük performans.

Bir başka sorun da, uygulamanızın, kullanıcınız sadece açmış olmasına rağmen hiçbir işlem yapmamasına rağmen her zaman bir bağlantıya sahip olacağıdır. herhangi bir şey.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.