"Buka / tutup" SqlConnection atau tetap buka?

122

Saya menerapkan logika bisnis saya dalam kelas statis sederhana dengan metode statis. Masing-masing metode ini membuka / menutup koneksi SQL saat dipanggil:

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

        // ...

        connection.Close();
    }
}

Tapi saya pikir menghindari membuka dan menutup koneksi menghemat kinerja . Saya membuat beberapa tes lama sekali dengan kelas OleDbConnection (tidak yakin tentang SqlConnection), dan itu pasti membantu untuk bekerja seperti ini (sejauh yang saya ingat):

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

Jadi pertanyaannya adalah - haruskah saya memilih metode (a) atau metode (b)? Saya membaca pertanyaan stackoverflow lain bahwa penyatuan koneksi menghemat kinerja bagi saya, saya tidak perlu repot sama sekali ...

PS. Ini adalah aplikasi ASP.NET - koneksi hanya ada selama permintaan web. Bukan win-app atau layanan.

Alex
sumber
1
Hanya saran: Gunakan DbConnection.StateChangeacara untuk memantau perubahan dalam perubahan status koneksi (dan mungkin disimpan secara lokal) daripada memeriksa DbConnection.Stateproperti secara langsung. Ini akan menghemat biaya kinerja Anda.
deklon
1
Satu detail yang hilang adalah bagaimana metode ini menjadi bagian dari permintaan halaman. Apakah ini satu-satunya metode yang dipanggil atau itu, seperti yang saya asumsikan dalam tanggapan saya, salah satu dari banyak metode yang disebut di halaman reqest, itu mempengaruhi jawaban mana yang benar;)
David Mårtensson
David - BANYAK metode seperti ini disebut :)
Alex
1
Kasus A menunjukkan kurangnya kepercayaan pada Buang: lihat stackoverflow.com/questions/1195829/… dan contoh di MSDN msdn.microsoft.com/en-us/library/…
user2864740

Jawaban:

82

Tetap berpegang pada opsi a .

Penyatuan koneksi adalah teman Anda.

Adriaan Stander
sumber
37
IMHO - dia bahkan seharusnya tidak dekat. pembuangan akan melakukannya.
Royi Namir
2
@RoyiNamir Saya agak suka panggilan untuk menutup koneksi. Khusus untuk pemula dan pendatang baru di basis kode. Ini lebih eksplisit dan mudah dibaca.
edhedges
27
@edhedges Memanfaatkan "using" dan Close () pada akhirnya hanya akan menyebabkan kebingungan bagi pendatang baru. Mereka tidak akan memahami tujuan dari menggunakan "menggunakan". Jangan gunakan "Tutup" sebagai gantinya ajari mereka tujuan "menggunakan". Sehingga mereka dapat belajar menjadi lebih baik dan menerapkan apa yang mereka pelajari ke bagian lain dari kode.
Luis Perez
1
Haruskah / apakah "Open ()" perlu dipanggil? Saat ini saya menggunakannya seperti ini: using (var conn = GetConnection ()) {} public SqlConnection GetConnection () {return new SqlConnection (_connectionString); }
ganders
79

Gunakan Metode (a), setiap saat. Ketika Anda mulai menskalakan aplikasi Anda, logika yang berhubungan dengan negara akan menjadi sangat menyakitkan jika Anda tidak melakukannya.

Penyatuan koneksi melakukan apa yang tertulis di kaleng. Coba pikirkan apa yang terjadi saat skala aplikasi, dan seberapa sulit mengelola status buka / tutup koneksi secara manual. Kumpulan koneksi melakukan pekerjaan yang baik untuk menangani ini secara otomatis. Jika Anda khawatir tentang kinerja, pikirkan tentang semacam mekanisme cache memori sehingga tidak ada yang diblokir.

WeNeedAnswers
sumber
33

Selalu tutup koneksi segera setelah Anda selesai menggunakannya, sehingga koneksi database yang mendasarinya dapat kembali ke kumpulan dan tersedia untuk pemanggil lain. Penyatuan koneksi dioptimalkan dengan cukup baik, jadi tidak ada penalti yang nyata untuk melakukannya. Nasihatnya pada dasarnya sama dengan untuk transaksi - buat agar tetap pendek dan tutup saat Anda selesai.

Ini menjadi lebih rumit jika Anda mengalami masalah MSDTC dengan menggunakan satu transaksi di sekitar kode yang menggunakan banyak koneksi, dalam hal ini Anda benar-benar harus berbagi objek koneksi dan hanya menutupnya setelah transaksi selesai.

Bagaimanapun Anda melakukan hal-hal dengan tangan di sini, jadi Anda mungkin ingin menyelidiki alat yang mengelola koneksi untuk Anda, seperti Kumpulan Data, Linq ke SQL, Kerangka Kerja Entitas atau NHibernate.

Neil Barnwell
sumber
Anda tidak boleh membuka dan menutup koneksi secara normal dalam setiap panggilan metode, hanya sekali untuk setiap permintaan halaman. Setidaknya itulah yang telah saya pelajari;) Pembukaan dan penutupan membutuhkan waktu.
David Mårtensson
8
@David Martensson - koneksi tidak benar-benar dibuka dan ditutup saat Anda memanggil SqlConnection.Open. ASP.NET mendaur ulang sambungan aktif dari kolam saat string sambungan cocok dengan string sambungan yang digunakan sebelumnya. Overhead yang terlibat dalam hal ini tidak penting, dan sebagai tambahan, mencoba "melakukannya sendiri" berarti Anda harus memikul semua tugas manajemen untuk memastikan koneksi masih aktif untuk setiap penggunaan selanjutnya, yang menambah kompleksitas dan overhead. Dengan penggabungan koneksi, praktik terbaik adalah membuka dan menutupnya untuk setiap penggunaan.
Jamie Treworgy
2
Dengan segenap rasa hormat saya, jawaban "Selalu dekat hubungan" tidak sesuai dengan pertanyaannya ... Saya menutupnya. Pertanyaannya adalah - kapan.
Alex
@David Martensson "Sekali untuk setiap halaman" terlalu disederhanakan. Anda benar bahwa jika Anda memiliki beberapa perintah database untuk dijalankan satu demi satu, Anda dapat menjaga koneksi tetap terbuka saat Anda menjalankannya. Akan ada biaya tambahan kecil jika Anda menutup dan membuka kembali - koneksi akan masuk ke kolam dan diambil darinya beberapa saat kemudian.
Beton Gannet
1
@David Martensson Tapi jangan pernah menyimpan koneksi yang menganggur. Jika Anda menunggu tindakan dari pengguna atau hal lainnya, tutup. Jika ragu, tutup. Anda membuka selambat mungkin dengan harapan orang lain telah menyelesaikan koneksi dan mengumpulkannya. Kemudian Anda membalas budi - sedini mungkin.
Beton Gannet
13

Penafian: Saya tahu ini sudah tua, tetapi saya menemukan cara mudah untuk menunjukkan fakta ini, jadi saya memasukkan nilai dua sen saya.

Jika Anda kesulitan mempercayai bahwa penggabungan benar-benar akan menjadi lebih cepat, cobalah ini:

Tambahkan yang berikut ini di suatu tempat:

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

Sekarang ganti semua panggilan ke Open()dengan TimedOpen()dan jalankan program Anda. Sekarang, untuk setiap string koneksi berbeda yang Anda miliki, jendela konsol (keluaran) akan memiliki satu jendela yang berjalan lama, dan banyak yang terbuka sangat cepat.

Jika Anda ingin memberi label, Anda dapat menambahkan new StackTrace(true).GetFrame(1) + ke panggilan ke WriteLine.

Chris Pfohl
sumber
9

Ada perbedaan antara koneksi fisik dan logis. DbConnection adalah sejenis koneksi logis dan menggunakan koneksi fisik yang mendasari ke Oracle. Menutup / membuka DbConnection tidak memengaruhi kinerja Anda, tetapi membuat kode Anda bersih dan stabil - kebocoran koneksi tidak mungkin terjadi dalam kasus ini.

Anda juga harus ingat tentang kasus-kasus ketika ada batasan untuk koneksi paralel pada server db - dengan mempertimbangkan hal itu perlu membuat koneksi Anda sangat pendek.

Kumpulan koneksi membebaskan Anda dari pemeriksaan status koneksi - cukup buka, gunakan, dan segera tutup.

Tony Kh
sumber
Ya, koneksi bukanlah koneksi - yaitu DbConnection bukanlah koneksi fisik. DbConnection adalah kelas .NET yang menyediakan metode dan properti untuk memanipulasi koneksi fisik yang mendasarinya.
Beton Gannet
Sayangnya tidak segera jelas bahwa semua ini dilakukan secara implisit, tetapi dokumentasi menguraikannya. docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
Austin Salgat
2

Biasanya Anda harus menyimpan satu koneksi untuk setiap transaksi (tidak ada komputasi paralel)

mis. ketika pengguna melakukan tindakan pengisian, aplikasi Anda perlu menemukan saldo pengguna terlebih dahulu dan memperbaruinya, mereka harus menggunakan koneksi yang sama.

Meskipun ado.net memiliki kumpulan koneksi, biaya pengiriman koneksi sangat rendah, tetapi penggunaan kembali koneksi adalah pilihan yang lebih baik.

Mengapa tidak menyimpan hanya satu koneksi dalam aplikasi

Karena koneksi diblokir saat Anda menjalankan beberapa kueri atau perintah, itu berarti aplikasi Anda hanya melakukan satu operasi db pada waktu yang sama, betapa buruk kinerjanya.

Satu lagi masalah adalah bahwa aplikasi Anda akan selalu memiliki koneksi meskipun pengguna Anda hanya membukanya tetapi tidak ada operasi.Jika ada banyak pengguna yang membuka aplikasi Anda, server db akan membebani semua sumber koneksinya dalam waktu dekat sementara pengguna Anda tidak melakukannya apa pun.

ShiningRush
sumber