C# ve SQL Bağlantıları
SQL 7.0 ve yukarısı veritabanlarına bağlanırken kullandığımız SqlConnection
sınıfını properties* method ve eventleri ile gözden geçirmeye çalışacağız. SqlConnection classı System.Data.SqlClient namespace inden gelmektedir. Bu nedenle öncelikle. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; satırını ekleyerek SqlConnection ımızı kullanabilir hale getiriyoruz. Daha sonra bu class yardımıyla programımızda kullanabilmek için bir SqlConnection nesnesi türetelim. SqlConnection baglanti = new SqlConnection(); Şimdi SqlConnection la birlikte kullananabileceğimiz ve veritabanına bağlanırken bize avantaj* dezavantaj sağlayayan propertieslermizi inceleyelim. Öncelikle bir örnek olması açısından bu baglantımıza ait connection string’imizi yazıp daha sonra bu yazdıklarımızı tek tek inceleyelim. baglanti.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=true; connection lifetime=20; connection timeout=25; packet size=1024;"; Connection String Properties: Data Source: Bağlanacağımız bilgisayarın adı yada ip numarasını belirtiriz. Database: Bağlanacağımız database’in adını belirtiriz. Usser ID(uid): Bağlanacağımız sql veritabanına hangi kullanıcı adı ile gireceğimizi belirtiriz. Password (pwd):: user id mize ait şifremizi belirtiriz. Pooling: Database’ e birkere bağlanıp verileri okuduktan yada yazdıktan sonra database ile olan bağlantıyı ya biz sonlandırırız. Ya imleç connection nesnesinin etki alanından çıkınca otomatik olarak sonlandırılır. Yada database ile belli bir süre işlem yapmayınca devreye garbage collectors girerek bağlantının sonlanmasını sağlar. Bu tip durumlarda aynı veritabanından aynı yada daha fazla veriyi alırken kullanıcı performansın üst düzeyde olmasını hatta sanki bellekten okunuyormuş gibi olmasını ister. Pooling bu noktada devreye girer ve daha önce database’den alınmış olan verileri çok daha hızlı olarak tekrar istemciye gönderimesini sağlar. İki farklı değer alabilir. True olursa aktif* false olursa pasiftir. Dikkat etmemiz gereken nokta pooling yapısı aynı connection string ile oluşan bağlantılar için geçerlidir. Pooling’in özelliğinin sağladığı performans katkısını görmek için database ile olan bağlantımızı açıp kapatarak bir test yapalım. SqlConnection baglanti1 = new SqlConnection(); SqlConnection baglanti2 = new SqlConnection(); private **** Form1_Load(object sender* EventArgs e) { baglanti1.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=true; connection lifetime=10; connection timeout=5; packet size=1024;"; baglanti2.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=false; connection lifetime=10; connection timeout=5; packet size=1024;"; } private **** ac_Click_1(object sender* EventArgs e) { DateTime baslangic = DateTime.Now; for (int i = 0; i < 9999; i++) { baglanti1.Open(); baglanti1.Close(); } DateTime bitis = DateTime.Now; TimeSpan fark = bitis - baslangic; label1.Text = fark.TotalMilliseconds.ToString(); } private **** kapat_Click(object sender* EventArgs e) { DateTime baslangic = DateTime.Now; for (int i = 0; i < 9999; i++) { baglanti2.Open(); baglanti2.Close(); } DateTime bitis = DateTime.Now; TimeSpan fark = bitis - baslangic; label2.Text = fark.TotalMilliseconds.ToString(); } Gördüğünüz üzere pooling özelliği Sql bağlantılarımızda performansımıza yüksek düzeyde etkinlik sağlamaktadır. Min pool size: Aktif olabilecek minimum baglanti sayısını belirtir. Max pool size: Aktif olabilecek maksimum baglanti sayısını belirtir. Connection Lifetime: Açmış olduğumuz connection’ın ne kadar süre aktif olacağını bu özellikle belirleriz. Connection Timeout: Veritabanına bağlanırken zaman zaman server taraflı* zaman zaman client taraflı yada diğer iletişim problemleri nedeniyle bağlantının sağlanamadığı durumlar gerçekleşir. Bu durumlar* Programımızın ne kadar süre içinde veritabanına bağlanması gerektiğini hatta daha açık bir cümleyle… “ne kadar sürede veritabanına bağlanamazsa hata vereceğini” belirleriz. Default olarak değeri 15sn dir. Eğer connection stringde belirtmez isek. 15 sn olarak kabul edilir. Packet Size: Performans açısından çok önemli bir kriter olan packet size. Bağlantının kaç bytle’lık paketler halinde veri iletişimi sağlayacağını belirtir. Default olarak değeri 8192 byte olup minimum değeri: 512 maximum değeri: 32767 byte yani 32 kb’dır. Alacağımız verinin büyüklüğüne göre seçeceğimiz bu değer. Genellikle resim yada benzeri büyük boyutlu içerikler için 32767 text içerikler içinse daha düşük değerleri içermelidir. Bağlantı sağlanmadan önce connection stringde belirtilmesi gerektiği için baglanti.Open(); baglanti.PacketSize = 2048; gibi sonradan belirttiğimiz bir kullanımda hata oluşturacaktır. Properties State: Kod bloklarında çoğu zaman baglantinin ne zaman açılıp ne zaman kapandığı belirtmiş olsakta kullanıcının işlem yapma zamanını göz önünde bulundurduğumuzda baglantinin durumunu tekrar gözden geçirmemiz gerekir. Örneğin eğer bağlantı açıksa kullanıcının istediği işlemi tekrar bağlantı oluşturmadan daha hızlı yapmasını sağlayabilir. Yada bunun tam tersi durumlarda kullanıcı işlem yapmakta gecikmiş ise bağlantıyı yenilememiz gerektiğini bu özellik sayesinde öğrenebiliriz. SqlConnection baglanti = new SqlConnection(); private **** Form1_Load(object sender* EventArgs e) { baglanti.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=true; connection lifetime=20; connection timeout=5; packet size=1024; connection lifetime=5;"; baglanti.Open(); } private **** durum_Click(object sender* EventArgs e) { if (baglanti.State == ConnectionState.Open) { MessageBox.Show("bağlantı açık"); } else { MessageBox.Show("baglanti kapalı"); } } private **** ac_Click(object sender* EventArgs e) { if (baglanti.State == ConnectionState.Closed) // Açık olan bağlantıyı tekrar açmak hata mesajı üreteceğinden if döngüsüne aldık. { baglanti.Open(); } else { MessageBox.Show("Bağlantı zaten açık"); } } private **** kapat_Click(object sender* EventArgs e) { baglanti.Close(); } State yapsının öğrenebileceğimiz durumları şöyledir: a) Broken: Belirtilen bağlantı daha önce closed olmuş ve daha sonra tekrar açılmıştır. b) Closed: Bağlantı kapalı durumdadır. c) Connecting: Bağlantı kurulma aşamasındadır. d) Executing: Bağlantı üzerinde o anda bir komut işlem görmektedir. e) Fetching: Veri alışverişi yapılmaktadır. f) Open: Bağlantı Açıktır. Yazılın ilerleyen bölümlerinde StateChange olayını inceleyecek ve bu olay yardımıyla bağlantı durumu değiştiğinde direkt bilgi alabileceğimizi göreceğiz. ServerVersion: Çalıştığımız database in versiyonunu öğrenmemize yarar. Geriye server’ın versiyon bilgisini dönderir. Örnek kullanım: SqlConnection baglanti = new SqlConnection(); private **** Form1_Load(object sender* EventArgs e) { baglanti.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=true; connection lifetime=20; connection timeout=5; packet size=1024; connection lifetime=5;"; baglanti.Open(); } private **** durum_Click(object sender* EventArgs e) { if (baglanti.State == ConnectionState.Open) { MessageBox.Show("Database version: " + baglanti.ServerVersion); } else { MessageBox.Show("baglanti kapalı"); } SqlConnection Methods: ChangeDatabase: Bazı durumlarda bağlantımız açık iken connection stringde belirtilen database’den başka bir database geçmemiz ve ordaki verilere ulaşmamız gerekebilir. Bu durumlarda ChangeDatabase methodu ile aynı serverdaki başka bir database e geçebiliriz. Ancak unutmayalımki bu durumda diğer Database’e bağlanırken windows authentication yada mssql yetkili kullanıcı parolası kullanmamız gerekir. baglanti.ChangeDatabase("DigerDatabase"); CreateCommand: Database ile veri iletişimi sağlarken kullandığımız SqlCommand’larda hepimizin genellikle kullandığı 1-) SqlCommand KomutAdi = new SqlCommand("select * from tablo"* baglanti); yada 2-) SqlCommand KomutAdi = new SqlCommand(); KomutAdi.Connection = baglanti; Gibi satırlar ile… bilirizki hangi SqlCommand’ın hangi SqlConnection ile ilişkilendirildiğini belirtmemiz gerekir. SqlConnection sınıfına ait bu methodlada bağlantı açık konumdayken o bağlantıya ait yeni bir SqlCommand nesnesi yaratırız. Örnek kullanım: SqlCommand KomutAdi = baglanti.CreateCommand(); Open: Kapalı konumda olan bağlantının açılmasını sağlar. Dikkat edilmesi gereken iki nokta vardır. a) Açık olan bağlantıyı tekrar açmaya kalkarsanız hata verir. b) SQL bağlantılarında bağlantı oluşurken server’dan cevap alınamaması gibi durumlar farklı sebeplerden ötürü sıklıkla karşımıza çıkar. Bu yüzden Open methodunun kullanıldığı noktalarda try – catch blogu kullanmak yada daha farklı olarak connection timeout süresinden önce hatayı yakalayacak bir timer oluşturarak kullanıcıyı hata mesajı ile karşı karşıya getirmemek önem teşkil eder. Örnek kullanım: try { baglanti.Open(); } catch { MessageBox.Show("bağlantı kurulamadı"); } Close: Açık olan bağlantının kapatılmasını sağlar. Örnek Kullanım: Baglanti.Close(); Transaction ve Isolation Level’lar: Transaction database bağlantılarında en önemli yere sahip noktalardan biridir. Database’e bağlı iken yaptığınız işlemlerde oluşan local yada server taraflı yada diğer iletişim aksilikleri. Yada aynı anda başka bir client’la aynı database’e bağlı olduğunuz ve değişiklik yaptığınız durumlarda oluşabilecek birçok hata mevcuttur. Bu gibi durumlarda transaction kullanarak bu olası hatalardan bazılarının önüne geçmemiz mümkün olmasada verilerimizin kaybolmasına karşın güvenliğini sağlamamız mümkün. Örnek vermek gerekirse; Varsayalım belli işlemler ile puan topladığımız bir oyun programladık. Ve oyunumuza nick belirterek girişler sağlayabiliyor. Hatta topladığımız puanları bu nickler arasında birbirine göndererek paylaşımını da sağlayabiliyoruz. Böyle bir hikayede Oyuncu1 nick’i ile topladığımız 1000 puanın 500’ünü “Oyuncu2” adlı nick’e aktarıyoruz. Aktarma sırasında gerçekleşecek bir elektrik kesintisi yada benzeri anlık aksaklıklar sonucu Oyuncu1’den çıkmış olan 500 puan Oyuncu2’ye varmadan kaybolacaktır. İkinci bir varsayımda ise başka birinin size puan transfer ettiği bir durumda sizin sağladığınız bağlantıda 1000 puanınız olduğu görünürken o anda başka biri size puan transfer ediyor. Ancak siz puanınızı 1000 olarak görmeye devam ediyorsunuz. Bu varsayımda ise bağlantı sağlandığında veriler üzerindeki yetkinliğinizi tanımlamanız gerekiyor. Örnek kullanım: private **** durum_Click(object sender* EventArgs e) { SqlConnection baglanti = new SqlConnection(); SqlParameter AktarilacakPuan = new SqlParameter(); SqlParameter AktarilacakOyuncu = new SqlParameter(); AktarilacakPuan.ParameterName = "@puan"; AktarilacakPuan.Value = textBox2.Text; AktarilacakOyuncu.ParameterName = "oyuncu"; AktarilacakOyuncu.Value = textBox1.Text; SqlTransaction sqltrans = new SqlTransaction(); // Transaction nesnemizi yaratıyoruz baglanti.ConnectionString = "Data Source=localhost; database=yasindb; User ID=sa; Password=sirkecili; pooling=true; connection lifetime=100; connection timeout=25; packet size=2048;"; baglanti.Open(); SqlCommand ekle = baglanti.CreateCommand(); // baglanti adındaki SqlConnection nesnemizde kullanmak için komut yaratıyoruz. ekle.CommandType = CommandType.Text; ekle.CommandText = "update puanlar set puan=puan + @puan where oyuncu=@oyuncu"; ekle.Parameters.Add(AktarilacakPuan); try { sqltrans = baglanti.BeginTransaction(IsolationLevel.ReadCommi tted); // ReadCommited olarak çalışmasını istediğimiz transaction'ımızı başlatıyoruz. ekle.ExecuteNonQuery(); sqltrans.Commit(); // işlemin başarıyla gerçekleştiğini onaylıyoruz. Ve böylelikle puan karşı tarafa puan göndermiş oluyoruz. MessageBox.Show("aktarım başarıyla tamamlandı"); baglanti.Close(); } catch { sqltrans.Rollback(); // işlemin başarısız olduğunu belirterek transaction'ın başladığı noktaya dönüyor ve puanın gitmemesini sağlıyoruz MessageBox.Show("aktarım gerçekleştirilemedi"); } Not: verimiz commit olduktan sonra bizden düşmesi gereken puanı Önemli olan konunun anlaşılması düşüncesiyle es geçtim. Burdaki kodlamada belirttiğim sqltrans = baglanti.BeginTransaction(IsolationLevel.ReadCommi tted); satırındaki isolationLevel dikkatinizi çekmiştir. Şimdi bu level’ların ne anlama geldiğini sırayla inceleyelim. Chaos: O anda başkası database üzerinde değişiklik yapıyor ise sizin değişiklik yapmanıza izin vermez. ReadCommited : Database’e bağlandığınızda o anda başkası değişiklik yapıyorsa onun commit olmuş verilerine ulaşmanızı. Henüz onaylanmayan değişikliklerini görmemenizi sağlar. ReadUncommited: Başka birini değişiklik yaptığı anda kişinin verileri henüz commit olmamış dahi olsa onları görüntüleyebilmenizi sağlar. RepeatableRead: Siz verileri okur iken bağlantı sağlayan diğer Client’ların değişiklik yapmamasını sağlarsınız. Serializable: Database’deki tüm verileri dondurarak hiçbir satıra güncelleneme yapılamamasını ve yeni satır eklenememesini sağlar. SqlConnection events: StateChange: Bu event yardımıyla connection durumunda bir değişiklik meydana geldiğinde istediğimiz bir kod bloğunun işletilmesini sağlarız. Böylelikle bağlantı durumunda bir değişiklik olduğu anda bilgi almamızıda mümkün kılmış oluruz. Bunun için önce bağlantımızı oluşturacak. Daha sonra bu bağlantıya ait bir statechange eventi yaratacak. Ve bu event yardımıyla durum bilgisi değiştiğinde ekrana MessageBox çıkartıp durum bilgisinin hangi konumdan hangi konuma geçtiğini görünteleyeceğiz. Örnek Kullanım: SqlConnection baglanti = new SqlConnection(); // bağlantımızı oluşturuyoruz. private **** Form1_Load(object sender* EventArgs e) { baglanti.ConnectionString = "Data Source=localhost; database=yasindb; uid=sa; pwd=sirkecili; pooling=true; connection lifetime=10; connection timeout=5; packet size=1024;"; baglanti.StateChange += new StateChangeEventHandler(durumbilgisi); // kod ile oluşturduğumuz sqlconnection nesnemize ait durumbilgisi adında statechange eventi tanımlıyoruz. } private **** ac_Click_1(object sender* EventArgs e) { if (baglanti.State == ConnectionState.Closed) // bağlantı kapalıysa... { baglanti.Open(); // bağlantıyı açıyoruz. } } private **** kapat_Click_1(object sender* EventArgs e) { baglanti.Close(); // bağlantıyı kapatıyoruz. } private **** durumbilgisi(object sender* StateChangeEventArgs e) // oluşturduğumu durumbilgisi eventine StateChangeEventArgs parametresini vererek durum bilgisini gözlemliyoruz. { MessageBox.Show("Bağlantı " + e.OriginalState.ToString() + " konumundan " + e.CurrentState.ToString() + " konumuna geçti"); // bağlantı durumu değiştiğinde durumu gözlemliyoruz. } Dikkat ederseniz e.CurrentState ile bağlantının durum değiştirmeden önceki halini e.OriginalState’de o anki durumunu yansıtmaktadır. |
Bütün Zaman Ayarları WEZ +3.5 olarak düzenlenmiştir. şu Anki Saat: 02:50 AM . |