Maaf karena hanya berkomentar di tempat pertama, tetapi saya memposting hampir setiap hari komentar serupa karena banyak orang berpikir bahwa akan pintar untuk merangkum fungsionalitas ADO.NET menjadi 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 bukan 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 yang berbeda untuk koneksi. Ini berarti bahwa selama eksekusi aplikasi, banyak koneksi yang identik akan berulang kali dibuka dan ditutup. Untuk meminimalkan biaya pembukaan koneksi, ADO.NET menggunakan teknik pengoptimalan yang disebut connection pooling.
Penyatuan koneksi mengurangi berapa kali koneksi baru harus dibuka. Pooler mempertahankan kepemilikan koneksi fisik. Ini mengelola koneksi dengan menjaga tetap hidup 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. Saat aplikasi memanggil Tutup pada koneksi, pooler mengembalikannya ke kumpulan koneksi aktif yang terkumpul alih-alih menutupnya. Setelah koneksi dikembalikan ke pool, koneksi siap digunakan kembali pada panggilan Terbuka berikutnya.
Jadi jelas tidak ada alasan untuk menghindari membuat, membuka, atau menutup koneksi karena sebenarnya koneksi tersebut tidak dibuat, dibuka, dan ditutup sama sekali. Ini adalah "hanya" tanda untuk kumpulan koneksi untuk mengetahui kapan koneksi dapat digunakan kembali atau tidak. Tapi itu adalah tanda yang sangat penting, karena jika koneksi "sedang digunakan" (kolam koneksi mengasumsikan), koneksi fisik baru harus dibuka 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 sangat memengaruhi kinerja, tetapi juga menjadi sumber kesalahan buruk dan (tanpa menggunakan Transaksi) menjadi area pembuangan data.
Jika Anda bahkan menggunakan koneksi statis, Anda membuat kunci untuk setiap utas yang mencoba mengakses objek ini. ASP.NET pada dasarnya adalah lingkungan multithreading. Jadi ada peluang besar untuk kunci ini yang menyebabkan masalah kinerja terbaik. Sebenarnya cepat atau lambat Anda akan mendapatkan banyak pengecualian yang berbeda (seperti ExecuteReader Anda memerlukan Koneksi yang terbuka dan tersedia ).
Kesimpulan :
- Jangan gunakan kembali koneksi atau objek ADO.NET sama sekali.
- Jangan dibuat statis/dibagikan (di VB.NET)
- Selalu buat, buka (dalam hal Koneksi), gunakan, tutup, dan buang di tempat yang Anda butuhkan (dalam suatu metode)
- gunakan
using-statement
untuk membuang dan menutup (dalam hal Koneksi) secara implisit
Itu benar tidak hanya untuk Koneksi (walaupun paling terlihat). Setiap objek yang mengimplementasikan IDisposable
harus dibuang (paling sederhana dengan using-statement
), terlebih lagi di System.Data.SqlClient
ruang nama.
Semua hal di atas bertentangan dengan DB-Class khusus yang merangkum dan menggunakan kembali semua objek. Itulah alasan mengapa saya berkomentar untuk membuangnya. Itu hanya sumber masalah.
Sunting :Berikut ini kemungkinan penerapan retrievePromotion
. Anda -metode:
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 [email protected]";
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;
}