İlk başta yorum yaptığım için özür dilerim, ancak neredeyse her gün benzer bir yorum yayınlıyorum çünkü birçok kişi ADO.NET işlevselliğini bir DB Sınıfına yerleştirmenin akıllıca olacağını düşünüyor (ben de 10 yıl önce). Çoğunlukla, herhangi bir eylem için yeni bir nesne oluşturmaktan daha hızlı göründüğü için statik / paylaşılan nesneleri kullanmaya karar verirler.
Bu ne performans açısından ne de arıza güvenliği açısından iyi bir fikir.
Bağlantı Havuzu bölgesinde kaçak avlanma
ADO.NET'in, ADO-NET Bağlantı Havuzundaki DBMS'ye temeldeki Bağlantıları dahili olarak yönetmesinin iyi bir nedeni vardır :
Pratikte çoğu uygulama, bağlantılar için yalnızca bir veya birkaç farklı konfigürasyon kullanır. Bu, uygulamanın yürütülmesi sırasında birçok aynı bağlantının tekrar tekrar açılıp kapanacağı anlamına gelir. ADO.NET, bağlantı açma maliyetini en aza indirmek için bağlantı havuzu adı verilen bir optimizasyon tekniği kullanır.
Bağlantı havuzu oluşturma, yeni bağlantıların açılması gereken sayısını azaltır. Pooler, fiziksel bağlantının sahipliğini korur. Verilen her bağlantı yapılandırması için bir dizi etkin bağlantıyı canlı tutarak bağlantıları yönetir. Bir kullanıcı bir bağlantıda Aç'ı aradığında, saldırgan havuzda uygun bir bağlantı arar. Havuzlanmış bir bağlantı varsa, yeni bir bağlantı açmak yerine arayana geri gönderir. Uygulama bağlantıda Kapat'ı çağırdığında, pooler onu kapatmak yerine havuzlanmış etkin bağlantılar kümesine geri döndürür. Bağlantı havuza geri döndüğünde, bir sonraki Açık çağrıda yeniden kullanılmaya hazırdır.
Açıkçası, bağlantı oluşturmaktan, açmaktan veya kapatmaktan kaçınmak için hiçbir neden yok çünkü bunlar aslında oluşturulmuyor, açılmıyor ve kapanmıyor. Bu, bağlantı havuzunun bir bağlantının ne zaman yeniden kullanılıp kullanılamayacağını bilmesi için "yalnızca" bir işarettir. Ancak bu çok önemli bir bayrak, çünkü bir bağlantı "kullanımdaysa" (bağlantı havuzu varsayılır), çok pahalı olan yeni bir fiziksel bağlantının DBMS'ye açık olması gerekir.
Yani performans artışı elde etmiyorsunuz, tam tersi. Belirtilen maksimum havuz boyutuna ulaşılırsa (100 varsayılandır), istisnalar bile alabilirsiniz (çok fazla açık bağlantı ...). Bu nedenle, bu yalnızca performansı muazzam bir şekilde etkilemekle kalmayacak, aynı zamanda kötü hatalar için bir kaynak ve (İşlemleri kullanmadan) bir veri boşaltma alanı olacaktır.
Statik bağlantılar kullanıyorsanız bile, bu nesneye erişmeye çalışan her iş parçacığı için bir kilit oluşturuyorsunuz. ASP.NET, doğası gereği çok iş parçacıklı bir ortamdır. Bu nedenle, en iyi ihtimalle performans sorunlarına neden olan bu kilitler için büyük bir şans var. Aslında er ya da geç birçok farklı istisna ile karşılaşacaksınız ( ExecuteReader'ınızın açık ve kullanılabilir bir Bağlantı gerektirmesi gibi ).
Sonuç :
- Bağlantıları veya herhangi bir ADO.NET nesnesini yeniden kullanmayın.
- Bunları statik / paylaşımlı yapmayın (VB.NET'te)
- Her zaman oluşturun, açın (Bağlantılar olması durumunda), kullanın, kapatın ve ihtiyaç duyduğunuz yerde imha edin (bir yöntemde fe)
using-statement
imha etmek ve kapatmak için kullanın (Bağlantılar durumunda) dolaylı olarak
Bu sadece Bağlantılar için geçerli değil (en dikkat çekici olmasına rağmen). Gerçekleştirilen her nesne , ad alanında daha fazlası olmak üzere, IDisposable
elden çıkarılmalıdır (en basit şekilde using-statement
) System.Data.SqlClient
.
Yukarıdakilerin tümü, tüm nesneleri kapsülleyen ve yeniden kullanan özel bir DB Sınıfına karşı konuşuyor. Onu çöpe atmak için yorum yapmamın nedeni bu. Bu sadece bir sorun kaynağı.
Düzenleme : İşte- retrievePromotion
yönteminizin olası bir uygulaması :
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;
}