Bütün veritabanı işlemlerinde bir connection tanımlar ve bunun vasıtasıyla veritabanımıza bağlanıp istediğimiz işlemleri yaparız. Farklı her connection tanımladığımızda bu connectionlar connection pool’da saklanır. Eğer tekrar aynı connectiona ihtiyaç duyarsak tekrar tanımlama yaparız, ama artık bu yeni bir connection olmayıp pool’dan bize atanır. Böylelikle aynı veritabanına defalarca bağlanırken (üstelik kullanıcı sayısının arttığını da düşünürsek) daha kısa sürede bağlantı yapmamızı sağlayacaktır. Bu da daha fazla performans demektir.
Şimdi bu connection pooling ile karşılaşabileceğimiz bir sorunun senaryosunu hazırlayalım. Öncelikle aşağıdaki örnek kodumuzu ele alalım:
|
SqlConnection con = new SqlConnection (“server=.SQLEXPRESS;database=TEST;UId=User1;Pwd=123;”); SqlCommand cmd = new SqlCommand (“SELECT Count(*) FROM TARIH”, con); con.Open(); int i = Convert.ToInt32(cmd.ExecuteScalar()); con.Close(); //Bir takım işlemler…. SqlConnection con2 = new SqlConnection (“server=.SQLEXPRESS;database=master;UId=sa;Pwd=123; Pooling=False“); SqlCommand cmd2 = new SqlCommand (“ALTER DATABASE TEST SET READ_ONLY”, con2); try { con2.Open(); cmd2.ExecuteNonQuery(); } catch (SqlException ex) { Console.WriteLine(ex.Message); } finally { con2.Close(); } |
Burada yapılanı incelersek TEST veritabanına User1 kullanıcısı ile bağlanıp bir sorgu çalıştırılıyor. Burada ne yapıldığı önemli değil, sonuçta veritabanına bağlanıp bir işlem yapıldığını görmek yeterli. Senaryomuz gereği bu veritabanı üzerinde bir işlem yapmamız gereksin. Bu herhangi bir işlem olabilir, basit olması açısında veritabanını READ_ONLY yapmaya çalışacağız. (Önemli olan alter database edebilmek) Buraya kadar bir sorun yokken çalışma zamanında aşağıdaki hata ile karşılaşıyoruz.
|
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ALTER DATABASE statement failed. |
Peki, bu da nereden çıktı şimdi? Evet, connection poolingden… Öncelikle ilk connectionı yarattığımızda bu connection poola atıldı. Daha sonra sa ile sisteme bağlanıp TEST veritabanı üzerinde alter database yapmak istediğimizde ise bize yukarıdaki hatayı verdi. SQLexpress management studioyu açıp sp_who ile bağlı kullanıcılara bakalım.

Sonuçlara baktığımızda User1 kullanıcısının bağlı olduğunu ama “uyuduğunu” görüyoruz. Bu da bizim daha sonra sa ile bu veritabanı üzerinde işlem yapmamızı engelliyor. (SQL 2000 kullanıyorsanız kod tarafında “database currently in use” mesajını alırsınız.)
Gelelim çözümümüze. En basiti, ilk bağlantımızı tanımlarken Pooling=False özelliğini eklemek olabilir. Ancak bu durumda connection poolingin bize sağladığı nimetlerden faydalanamayacağız ki bu istediğimiz bir çözüm değil. Bu durumda 2. bağlantımızı çalıştırmadan hemen önce
|
SqlConnection.ClearPool(con); |
komutunu işletebiliriz. Böylelikle bu connectionı pool’dan temizlemiş oluruz. Buradaki senaryomuzda aynı scope içinde işlem yaptık. Scope dışında isek aynı connectionı pooldan alıp temizleyebilmek için tekrar tanımlamamız gerekiyor. Yani:
|
SqlConnection con = new SqlConnection (“server=.SQLEXPRESS;database=TEST;UId=User1;Pwd=123;”); SqlConnection.ClearPool(con); |
Hemen burada farklı bir sorunun senaryosunu çizmek istiyorum. Peki, pool bu şekilde değil de farklı bir biçim de temizlenirse ne olur? Mesela sql serverda sorun oldu ve restart oldu, ya da sql admin gitti bizim bu User1 bağlantımızı bize haber vermeden KILL etti. (Yukarıdaki sp_who tablosuna göre KILL 53 komutu ile bağlı kullanıcı düşürülebilir.) Bu durumda poolda engel olacak kullanıcı olmadığından bizim ALTER DATABASE işlemi başarıyla çalışacaktır. Ancak, oldu ya daha sonra yine bizim bu veritabanı üzerinde işlem yapmamız gerekti:
|
SqlConnection con4 = new SqlConnection (“server=.SQLEXPRESS;database=TEST; UId=User1; Pwd=123;”); SqlCommand cmd4 = new SqlCommand (“SELECT Count(*) FROM TARIH”, con4); try { con4.Open(); int i2 = Convert.ToInt32(cmd4.ExecuteScalar()); } catch (SqlException ex) { Console.WriteLine(ex.Message); } finally { con4.Close(); }
|
Bu seferde farklı bir hata ile karşılaşıyoruz:
|
A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 – Borunun diğer ucunda işlem yok.) |
Anlaşılacağı üzere “borunun diğer ucu” gitmiş.Yani, ADO.NET bunun daha önce poolda olduğunu zannediyor ve connectionı bu şekilde tanımlıyor ve işlem yapmaya çalışıyor; ancak başarılı olamıyor. Peki, bu durumda ne olacak? Bu durumda yapılacak şey yine exceptiona düştüğünde poolu temizlemek:
|
catch (SqlException ex) { if (ex.Number == 233) { SqlConnection.ClearAllPools(); } } |
Bu durumda, eğer, bu sorgu çok kritik bir sorgu ise tekrar çalıştırılması gerekecektir.
Entries (RSS)