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.
__________________
بِسْــــــــــــــــــــــمِ اﷲِارَّحْمَنِ ارَّحِيم
-------------------------------------------------
Bu Soysuzlar Bu Vatansızlar Sarsada Yurdumu Ben Yaratan'dan Alırım Asil Kanı ve Gücü. -------------------------------------------------
|