Maaf karena hanya berkomentar di tempat pertama, tetapi saya memposting komentar serupa hampir setiap hari karena banyak orang berpikir bahwa akan cerdas untuk merangkum fungsionalitas ADO.NET ke dalam DB-Class (saya juga 10 tahun yang lalu). Sebagian besar mereka memutuskan untuk menggunakan objek statis / bersama karena tampaknya lebih cepat daripada membuat objek baru untuk tindakan apa pun.
Itu bukanlah ide yang baik dalam hal kinerja maupun dalam hal keamanan gagal.
Jangan berburu di wilayah Connection-Pool
Ada alasan bagus mengapa ADO.NET secara internal mengelola Koneksi yang mendasari ke DBMS di ADO-NET Connection-Pool :
Dalam praktiknya, sebagian besar aplikasi hanya menggunakan satu atau beberapa konfigurasi berbeda untuk koneksi. Ini berarti bahwa selama eksekusi aplikasi, banyak koneksi identik yang akan dibuka dan ditutup berulang kali. Untuk meminimalkan biaya pembukaan koneksi, ADO.NET menggunakan teknik pengoptimalan yang disebut penggabungan koneksi.
Penggabungan koneksi mengurangi berapa kali koneksi baru harus dibuka. Pooler mempertahankan kepemilikan koneksi fisik. Ia mengelola koneksi dengan tetap menghidupkan satu set koneksi aktif untuk setiap konfigurasi koneksi yang diberikan. Setiap kali pengguna memanggil Buka pada koneksi, pooler mencari koneksi yang tersedia di pool. Jika koneksi gabungan tersedia, itu mengembalikannya ke pemanggil alih-alih membuka koneksi baru. Ketika aplikasi memanggil Tutup pada koneksi, pooler mengembalikannya ke kumpulan koneksi aktif alih-alih menutupnya. Setelah koneksi dikembalikan ke kolam, itu siap untuk digunakan kembali pada panggilan Terbuka berikutnya.
Jadi jelas tidak ada alasan untuk menghindari membuat, membuka atau menutup koneksi karena sebenarnya mereka tidak dibuat, dibuka dan ditutup sama sekali. Ini "hanya" sebuah tanda untuk kumpulan koneksi untuk mengetahui kapan koneksi dapat digunakan kembali atau tidak. Tetapi itu adalah tanda yang sangat penting, karena jika koneksi sedang "digunakan" (asumsi kumpulan koneksi), koneksi fisik baru harus openend ke DBMS yang sangat mahal.
Jadi Anda tidak mendapatkan peningkatan kinerja tetapi sebaliknya. Jika ukuran kumpulan maksimum yang ditentukan (100 adalah default) tercapai, Anda bahkan akan mendapatkan pengecualian (terlalu banyak koneksi terbuka ...). Jadi ini tidak hanya akan berdampak besar pada kinerja tetapi juga menjadi sumber kesalahan yang parah dan (tanpa menggunakan Transaksi) area-dumping-data.
Jika Anda bahkan menggunakan koneksi statis, Anda membuat kunci untuk setiap utas yang mencoba mengakses objek ini. ASP.NET adalah lingkungan multithreading secara alami. Jadi ada peluang besar untuk kunci ini yang paling banyak menyebabkan masalah kinerja. Sebenarnya cepat atau lambat Anda akan mendapatkan banyak pengecualian berbeda (seperti ExecuteReader Anda membutuhkan Koneksi terbuka dan tersedia ).
Kesimpulan :
- Jangan gunakan kembali koneksi atau objek ADO.NET sama sekali.
- Jangan membuatnya statis / dibagikan (di VB.NET)
- Selalu buat, buka (dalam kasus Koneksi), gunakan, tutup dan buang di mana Anda membutuhkannya (fe dalam suatu metode)
- gunakan
using-statement
untuk membuang dan menutup (dalam kasus Koneksi) secara implisit
Itu benar tidak hanya untuk Koneksi (meskipun paling menonjol). Setiap implementasi objek IDisposable
harus dibuang (paling sederhana oleh using-statement
), terlebih lagi di System.Data.SqlClient
namespace.
Semua hal di atas menentang DB-Class kustom yang merangkum dan menggunakan kembali semua objek. Itulah alasan mengapa saya berkomentar untuk membuangnya. Itu hanya sumber masalah.
Sunting : Berikut kemungkinan penerapan retrievePromotion
-method Anda :
public Promotion retrievePromotion(int promotionID)
{
Promotion promo = null;
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MainConnStr"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
var queryString = "SELECT PromotionID, PromotionTitle, PromotionURL FROM Promotion WHERE PromotionID=@PromotionID";
using (var da = new SqlDataAdapter(queryString, connection))
{
// you could also use a SqlDataReader instead
// note that a DataTable does not need to be disposed since it does not implement IDisposable
var tblPromotion = new DataTable();
// avoid SQL-Injection
da.SelectCommand.Parameters.Add("@PromotionID", SqlDbType.Int);
da.SelectCommand.Parameters["@PromotionID"].Value = promotionID;
try
{
connection.Open(); // not necessarily needed in this case because DataAdapter.Fill does it otherwise
da.Fill(tblPromotion);
if (tblPromotion.Rows.Count != 0)
{
var promoRow = tblPromotion.Rows[0];
promo = new Promotion()
{
promotionID = promotionID,
promotionTitle = promoRow.Field<String>("PromotionTitle"),
promotionUrl = promoRow.Field<String>("PromotionURL")
};
}
}
catch (Exception ex)
{
// log this exception or throw it up the StackTrace
// we do not need a finally-block to close the connection since it will be closed implicitely in an using-statement
throw;
}
}
}
return promo;
}