Veritabanı etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Veritabanı etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

TFS 2010 yükseltme, TFS 2012 ye göç ( TFS 2010 upgrage, TFS 2012 migration)

TFS 2010 versiyonundan 2012 versiyonuna yükseltmek için yazılmış birçok İngilizce kaynak bulabilirsiniz. Bu kaynaklarda söz edilmeyen bazı ipuçlarını paylaşalım:
  • TFS yükseltme çalışmasının alacağı süre veritabanı boyutlarınız ve sunucunun işlemci hızı ile doğrudan ilişkilidir.
  • Yükseltme işlemi veritabanındaki en büyük tablolar üzerinde yeni alanlar ekleme, index oluşturma ve kopyalama işlemleri ile veritabanının da güncellenmesini içeriyor.
  • 100 GB'lık bir veritabanı için yükseltme işlemi 3 saat kadar sürebilir.
  • Yükseltme işlemini başlattığınız pencerede çalışma durumu gösterge çubuğu ilerlemiyorsa veritabanındaki aktif işlemlerinizi ve tablo boyutlarındaki değişimleri takip etmeniz iyi olacaktır.

Kurulumu yapacak kullanıcının:

  • TFS kurulacak sunucuda Administrator grubunda olması
  • TFS yükseltmesi olacak veritabanında sysadmin yetkisinde olması
  • TFS Admin grubunda tanımlı olması gerekiyor.

Rastgele Sorgu Üreteci

SQL sunucularını sınamak için geliştirilmiş bir yazılım var: Random Query Generator

Nedense fikir hoşuma gitti. Özellikle işlev testi, stres testi gibi amaçlar için geliştirilmiş bu yazılım. İlgilisine duyurulur.

Oracle plsql de ref cursor örneği

Ref cursor kullanarak ihtiyacımı olan veri kümesi üzerinde çalışmaya bir örnek:
declare
type rec_musteri is record(
musteriNo number(20),
musteriAd varchar2(50));

rcMusteri omwb_emulation.globalpkg.RCT1;
erMusteri rec_musteri;

v_MusteriNo number(20);

begin

open rcMusteri for
select musterino, musteriAd
from tbl_musteri m
where m.tcknNo = TO_CHAR('01234567890');
exception
when others then
v_Hata := sqlerrm;

if rcMusteri%isopen then
loop
v_MusteriNo := '';
fetch rcMusteri
into erMusteri;
exit when rcMusteri%notfound;
v_MusteriNo := erMusteri.musteriNo;
v_MusteriAd := erMusteri.musteriAd;
end loop;
end if;
end;

Indeks kullanılmayan tablolar için iki SQL cümlesi

Indeks kullanmadığımız tablolarda bazen tüm kolonları aynı olan ya da benzer verilere sahip kayıtlar oluşur.

Bunlardan fazla olan kayıtları silmek için ROWID den yararlanabiliriz.

/*Birden çok kaydın fazla olanlarını silip tek kayda indirmek*/
DELETE from Tablo1 t where rowid NOT IN (select min(rowid) from Tablo1 b where t.ogrenci_no = b.ogrenci_no and t.kayit_durum = b.kayit_durum group by b.ogrenci_no, b.kayit_durum);



Tablolarda Indeksleme yapmadığımız alanlar için insert cümlesine kontroller ekleyebiliriz, böylece çift kayıt atılmasını önlemiş oluruz:

/*Insert cümlesinde kayıt durumu kontrolü*/
INSERT INTO tbl_ogrenci t (tbl_ogrenci_no, tbl_ogrenci_ad, tbl_kayit_durum) select 87, 'Eray', 'A' from dual where not exists (SELECT * FROM tbl_ogrenci o WHERE o.tbl_ogrenci_no = t.tbl_ogrenci_no AND o.tbl_kayit_durum = 'A');

DISTINCT yerine IN veya EXISTS

SQL cümlelerinde JOIN kullanımı sonucu tekrarlayan kayıtlar ile karşılaştığımız oluyor. Bunları tekil hale getirmek için DISTINCT kelimesini kullanabiliriz(1), ancak distinct sıralama ve filtreleme işlemi yapacağından sorgunun performansını azaltacaktır.
DISTINCT kullanmak yerine mümkünse JOIN ifadesinde kullanılan tablo ve koşullar ayrılarak altsorguya dönüştürülebilir, aranan değere ulaşmak için performansı bu tür durumlarda JOIN den daha yüksek olan IN veya EXISTS kullanılabilir(2).

(1)
select distinct m.musteri_no
from tbl_musteri m
join tbl_hesap h
on h.musteri_no = m.musteri_no
and h.kayit_durum = 'A'
and m.musteri_no = 123456

(2)
select m.musteri_no
from tbl_musteri m
where exists (select h.musteri_no
from tbl_hesap h
where h.musteri_no = m.musteri_no
and h.kayit_durum = 'A')
and m.musteri_no = 123456

Oracle da join için bir ipucu

Oracle da birkaç tabloyu join ile birleştirmeniz gerekiyorsa, sorgu sonucunun daha hızlı dönmesi için bu tablolardan daha az kayıt sayısı olanı ilk tablo olarak alın.

Örneğin

Tablo1 kayıt sayısı 100000
Tablo2 kayıt sayısı 20000
Tablo3 kayıt sayısı 4000 ise

select *
from Tablo2 t2
join Tablo1 t1 on t1.id = t2.id
left join Tablo3 t3 on t3.id = t2.id

şeklinde bir sorgu daha verimli çalışacaktır.

Tablo3'e left join ile gittiğimiz için daha az kayıt olmasına rağmen ilk tablo olarak onu alamadık. Left - Right joinlerde bu yöntem kullanılamaz.

Oracle da SUM ile NVL kullanımı

/* 1. Aşağıdaki sorgu kriterlere uyan bir kayıt bulamazsa hiç satır getirmeyecektir*/
select tahsilat_ttr
into deger1
from tablo1
where musteri_no = -1
and kayit_drm = 'A';

/* 2. Aşağıdaki sorgu kriterlere uyan bir kayıt bulamazsa boş bir satır getirecektir*/
select sum(tahsilat_ttr)
into deger2
from tablo2
where musteri_no = -1
and kayit_drm = 'A';

/* 3. Aşağıdaki sorgu kriterlere uyan bir kayıt bulamazsa 0(sıfır) değerini getirecektir*/
select nvl(sum(tahsilat_ttr),0)
into deger3
from tablo3
where musteri_no = -1
and kayit_drm = 'A';


Burada 2. olasılıkta elde edilen değerin NULL olmasına dikkat edilmeli.
Örneğin burada elde edilen tutarı bir başka tutar ile toplayacak olursak,
2. değer NULL olduğu için toplamın sonucu da NULL olacaktır.

Sonuc := deger2 + deger3;

Bu durumda 3. sorgu doğru değer döndürse de 2. sorgu 3.den dönen değeri NULL a dönüştürmüş
ve hiç tutar yokmuş gibi NULL değer dönmüş olacaktır.

Vista üzerinde Mysql

.Net C# yazmak gerekli olunca kolayı seçip windows açtım, yoksa Linux dururken Vista' da ne işim var. Veritabanı olarak mysql kurdum, ilk defasında sorunsuz çalıştı ama bilgisayarı kapatıp tekrar açınca mysql deamon bir türlü başlatılamadı.

Bayağı uğraştıktan sonra Vista için de Linux gibi admin modu kavramına benzer birşeyler yaptıklarını hatırladım. Sonuç olarak Vista üzerinde mysql'i doğru kurdunuz ama mysqld servisinin doğrudan başlamasını veya mysql veritabanını çalıştırmadıysanız; "mysql system tray monitor" u run as administrator olarak çalıştırın ve tekrar deneyin.

Yazılım Mühendislerinin Bilmesi Gereken 10 Kavram

Yazılım mühendislerinin bilmesi gereken 10 kavram başlıklı bir yazı. Aşağıda yazdığım 10 kavramın yazılım mühendisleri tarafından bilinmesi gerektiği söyleniyor yazıda. Ayrıca yazıya yapılmış yorumlarda farklı kavramların da eklenmesi gerektiği önerilmiş. Yazının İngilizce olduğunu hatırlatırım.
  1. Arabirimler (Interface)
  2. Kurallar ve şablonlar
  3. Katmanlama
  4. Algoritma karmaşıklığı
  5. Hashing
  6. Önbellekleme
  7. Koşut zamanlılık (Concurrency)
  8. Bulut Hesaplama (Cloud Computing)
  9. Güvenlik
  10. İlişkisel Veritabanları

Oracle plsql ile iç içe kontroller (nested case) ve Rownum kullanımı

İçiçe kontroller oluşturmak (nested case):
SELECT
CASE
WHEN nvl(musteri.sigortatipi, 0) != 0 THEN --ilgili musterinin sigortası varsa
(select sum(sigorta.odenentutar)
from tblsigorta sigorta
on musteri.musteriNo = sigorta.musteriNo
and sigorta.tip = musteri.sigortatipi)
WHEN nvl(musteri.teminat, 0) != 0 THEN --ilgili musterinin teminatı varsa
(case
when teminat.tur = 1 then
sum(teminat.tutar)
when teminat.tur = 2 then
sum(teminat.tutar) + sum(teminat.odenmisler)
else
0
end) END "ToplamOdenebilirTutar"

FROM tblmusteri musteri
INNER JOIN tblteminat teminat ON musteri.musteriNo = teminat.musteriNo

Rownum kullanımı:

T-SQL de "SELECT TOP n" ifadesi ile bir veri kümesinin ilk n kaydını çekebiliriz. PLSQL de ise bunun için "ROWNUM = n" ifadesinden yararlanmak gerekir. Aşağıdaki örnekte 2 nolu sınıftaki en küçük numaralı öğrenciyi çeken cümleyi görebiliriz.

SELECT ogr.adi FROM ogrenci ogr WHERE ROWNUM = 1 AND ogr.sinif = 2 ORDER BY ogr.ogrencino ASC;

Buna alternatif olarak MIN() ve GROUP BY ifadeleri ile de aynı sonuca ulaşabilirdik:

SELECT MIN(ogr.ogrencino), ogr.adi FROM ogrenci ogr WHERE ogr.sinif = 2 GROUP BY ogr.adi

JDBC Programlama için 5 Öneri

Java ile veritabanı erişimi için JDBC kullanmayı daha önce anlatmıştım. Bu anlatım yeni başlayanlar için bazı basit ve temel bilgileri içeriyordu. JDBC'yi artık sıklıkla kullandığınızı düşünelim, ve bir günlük yazısında karşılaştığım önemli önerileri paylaşalım:

1. Bağlantıları kapatın: Ne olursa olsun, hata ile karşılaşsanız bile sql bağlantılarını kapatın, kapatmayı unutmayın. Bu pratiği unuttuğunuzda programınızın hiç beklemediğiniz sorunlarla karşılaştığını görebilirsiniz. Elbette bu pratik yerine kullanılabilecek başka bir çözüm de bağlantı havuzu kullanımıdır. Böylece izin verilen bağlantı sayısını ve bunların kontrolünü sağlayabilirsiniz.

Kod Örneği:

Connection con;
try {
  con = …
} finally {
  try { if(con!=null) {con.close();}}
  catch (Exception e1) {}
}

2. Standart "Statement" yerine "PreparedStatement" kullanın: PreparedStatement kullanımı size bir çok avantaj sağlayacaktır (sağlıklı sorgular, düzenli girdi/çıktı şeklinde sorgular, başarım artışı). Bu yüzden sağlıklı bir şekilde PreparedStatement kullanmak gereklidir:

Örnek:
Statement statement = con.createStatement();
statement.executeQuery(“SELECT name FROM widgets WHERE type = ‘WidgetB’”);

Yerine:
final String widgetType = “WidgetB”;
Statement pStatement = con.prepareStatement(“SELECT name FROM widgets WHERE type = ?”);
pStatement.setString(1,widgetType);
pStatement.executeQuery();

3. Veritabanı platformu değişimlerine hazırlıklı olmak: Her zaman kullanıcıların isteği veya kendi kararınızla veritabanı değiştirebilirsiniz. Buna her zaman hazırlıklı olmanız gerekir. Yarın öbür gün MySQL kullandığınız bir program için PostgreSQL kullanmaya karar verebilirsiniz (Bkz: En sondaki yorumum)

4. Hiç bir zaman veritabanı sistemine özgü kütüphanedeki sınıfları kullanmayın: OracleCallableStatement cst = (OracleCallableStatement)conn.prepareCall şeklinde bir kullanım yaptığınızda bilin ki eğer Oracle'dan vazgeçmek zorunda kalırsanız kodu da aynı şekilde değiştirmeniz gerekecektir. Bu yüzden sadece JDBC tarafından sağlanan ve Java ile her zaman dağıtılan genel sınıfları kullanın.

5. Veritabanı stored procedure'leri kullanmayın: Yaşadığım özel sektör deneyimlerinden ve kişisel projelerimden yola çıkarak söyleyebilirim ki, en nefret ettiğim şey stored procedure kullanımıdır. Sizi veritabanı sistemine mahkum eder, değiştirmek zordur uzmanlık ister. Projenize özgü ve Java ile yapabileceğiniz hiç bir şeyi stored procedure ile yapmayın.

6. JSP içerisinde JDBC kodu kullanmayın: Bu herkesin bilmesi gereken bir şeydir. Dinamik web dosyalarınızın içerisine (PHP olsun, JDBC olsun) veritabanı sorgularını koymamak gerekir. Bunun için soyutlama yaparak başka sınıfları sorumlu tutup, işleri o sınıfta yapmanız makbul olan yoldur (Araştırınız: MVC, Üç katmanlı mimari, vb.).

Ek yorumum: Yukarıdaki zorluklardan bir kısmından kurtulmak istiyorsanız kalıcı katman kullanmaya çalışmalısınız. Başlangıç için

Veritabanı Bağlantılarında Oledb Metodları

.Net ortamında uygulama geliştirirken veritabanı erişimi, prosedür ve fonksiyon çağrımları için Oledb metodlarından faydalanıyoruz. NHibernate benzeri Kalıcı katmalara geçiş yapamadıysanız, bu metodları doğrudan kod içinde yada bizdeki gibi altyapınıza gömerek kullanmanız gerekecektir.

Qledb veri erişim ve prosedür/fonksiyon çağrımlarını yaparken kullandığımız metodları özetlersek[1]:

ExecuteNonQuery Satır Döndürmeyen bir komutu çalıştırır
ExecuteDataset Dataset olarak satırlar döndürür
ExecuteReader SqlDataReader olarak satırlar döndürür
ExecuteScalar Bir nesne olarak tek bir değer döndürür
ExecuteXmlReader XmlReader içinde bir Xml döndürür
FillDataset Gönderilen parametrelere göre Dataset'i doldurur
UpdateDataset Verilen update,insert,delete komutlarına göre DataSet in satırında değişiklik yapar
CreateCommand Verilen Stored Procedure ve Parametrelere göre Command nesnesi yaratır
ExecuteNonQueryTypedParams Herhangi bir satır döndürmeyen bir komutu çalıştırır
ExecuteDatasetTypedParams DataRow'un sütun değerlerini parametre olarak kullanıp DataSet döndüren bir komut işletir.
ExecuteReaderTypedParams DataRow'un sütun değerlerini parametre olarak kullanıp SqlDataReader döndüren bir komut işletir.
ExecuteScalarTypedParams DataRow'un sütun değerlerini parametre olarak kullanıp nesnenin değerini döndüren bir komut işletir.
ExecuteXmlReaderTypedParams XMLReader içersinde DataRow'un sütun değerlerini parametre olarak kullanan bir XML döndüren bir komut işletir

İhtiyacımız olduğunda en uygun olanını seçebilmek için bu metodların aklımızda olması iyi olacaktır. Böylece verimliliği de arttırmış oluruz.

Bazı hallerde değişse de(*) genelleyecek olursak, en çok kullanılan metodlar ve kullanıldıkları durumlar şöyle:
Birden çok kayıt döndürecek SELECT cümleleri ve bunları içeren prosedür/fonksiyon lar için; örneğin sürekli değişmeyen ve/veya büyük veri kümeleri ile çalışmamız gerekiyorsa "ExecuteDataset", anlık ve küçük verilere ihtiyacımız varsa "ExecuteReader" kullanabiliriz.

Tek kayıt döndürecek SELECT cümleleri ve bunları içeren prosedür/fonksiyon lar için ExecuteScalar tercih edilir.

INSERT/UPDATE/DELETE yapacak işlemler için ExecuteNonQuery kullanılır.


Hazır altyapıları kullanan yada kendi altyapısını geliştirmiş ekiplerde bu seviyedeki bağlantı metodları genellikle Veritabanı bağlantısı için hazırlanmış sınıflar içine gömülmüş oluyor. Geliştiriciye düşen bir veritabanı nesnesi yaratıp, bağlan/çalıştır gibi metodları çağırmak oluyor.

İş hayatına yeni başlayan biri için bu tür ekiplerde işe başlamak, getirdiği avantajlar çok olsa da, işin altyapısını öğrenmeyi zorlaştırıyor. Bize sunulan çerçevenin dışına taşmaya uğraşmalıyız.


*UPDATE cümlesinin kaç kaydı etkilediğini döndürmek gerektiğinde.

Kaynaklar:

[1]http://www.aspnedir.com/Article/DisplayArticle.aspx?ID=642

JDBC, Veritabanları, Classpath Falan Filan

JDBC Uygulama arabirimi (API) herhangi bir tablosal veriye, özellikle ilişkisel veritabanlarında (RDMS) veriye erişmek için kullanılan Java API'sidir. JDBC aşağıdaki üç programlama etkinliğini yöneten java uygulamaları yazmamızda yardımcı olur:
  1. Bir veritabanı bağlanma
  2. Veritabanına sorgular ve güncelleme cümleleri gönderme
  3. Sorgumuza cevap olarak gelen sonuçları alma ve işleme
Aşağıdaki basit kod parçacığı yukarıdaki üç adımı gerçekleştiren basit bir örneği göstermektedir:

// ilgili veritabanina bir baglanti yaratiyoruz
Connection con = DriverManager.getConnection("jdbc:myDriver:wombat", "myLogin","myPassword");
//sorguyu calistiracagimiz Statement yaratiyoruz 
Statement stmt = con.createStatement();
// sorguyu calistiralim, sonuclar ResultSet tipinde olacaktir
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); 
// elde ettigimiz sonuclari dolasip gelen her bir satirin verilerine ulasalim 
while (rs.next()) {
 int x = rs.getInt("a");
 String s = rs.getString("b");
 float f = rs.getFloat("c");
}

Bu basit kod parçacığı DriverManager yardımıyla parametrelerle belirlenmiş olan veritabanına bir bağlantı yaratıyor, bağlantı için giriş yapıyor. SQL sorgumuzu veritabanına taşıyacak olan Statement nesne örneği oluşturuyor. ResultSet nesnesini sorgumuzu çalıştırarak yaratıyor. Basit bir while döngüsü içerisinde sorgu sonuçlarını teker teker alıp işliyor.

JDBC kullanımı yukarıdaki adımlar doğrultusunda oldukça kolaydır. Bu kolaylığı çoğu kişi için zorlu bir hale getiren kısım bağlantı alma kısmıdır. Bağlantıyı sorunsuz bir şekilde aldıktan sonra bu bağlantı üzerinde Statement ve PreparedStatement kullanarak sorgu çalıştırmanın herhangi bir zorluğu yoktur.

Kullanılan veritabanına göre bağlantı alma kısmı çok az değişiklik gösterir. Bağlantısını alacağımız veritabanıyla ilgili olarak o veritabanının hangi sürücüsünü kullanacağımızı, hangi veritabanına bağlanacağımızı ve hangi kullanıcı adı ve şifresini kullanacağımızı belirtmemiz gerekir. Bu bilgileri doğru bir şekilde verdikten sonra bağlantı almada herhangi bir sorun çıkmayacaktır. Bu noktada acemi kullanıcıların en çok zorlandıkları kısım ilgili veritabanının JDBC sürücülerine ulaşmak ve bu sürücüleri kullanmaktır. Aşağıda sık kullanılan veritabanları ve ilgili JDBC sürücülerine erişmek üzere bağlantı adresleri vardır:

MySQL tarafından sunulan ve JDBC gerçekleştirimi sunan doğal Java sürücüsünün adı Connector/J'dir. Şu adresten indirilebilir.

Microsoft SQL Server için kullanılan JDBC sürücüsü adresinden indirilebilir.

Oracle için gereken JDBC sürücüleri adresinden indirilebilir

PostgreSQL için gereken JDBC sürücüleri adresinden indirilebilir.

Java DB, Java ile birlikte dağıtılan ve verileri dosya biçiminde saklayan eski adı Derby olan veritabanı, ayrıntılı bilgi için tıklayın.

Bunların dışında herhangi bir veritabanı kullanılıyorsa google arama motorunda Veritabani Yönetim Sistemi adı ile birlikte JDBC Driver anahtar kelimeleri birlikte kullanılarak ("MySQL JDBC Driver" şeklinde mesela) sürücüleri varsa erişmek mümkündür. Bu yukarıdaki sürücülere ek olarak farklı firmaların ücretli ve ücretsiz sunabildiği farklı JDBC sürücü çözümleri de vardır. Bu çözümlerden uygun olanı seçmek tamamen programcının ve firmanın tercihine kalmıştır.

Sürücünün sorunsuz elde edildiğini varsayarak, Eclipse üzerinde MySQL veritabanına bağlanan oldukça basit bir veritabanı kullanan örnek proje anlatmaya çalışayım.

Yaptığım bu örnek projede kullandığımız veritabanında Deneme isminde tek bir tablo ve bu tablonun da Saha isminde tek bir sahası var. Yazacağım oldukça basit örnek bu sahaya o anki zamanı (System.currentTimeMillis() ile alınan) yazacak ve tablodaki tüm verileri çeken bir sorgu çalıştırıp, o verileri ekrana yazacak.

Bu projenin asıl can alıcı kısmı DBConnectionManager sınıfıdır. Bu sınıf veritabanı bağlantıları için bir bağlantı havuzu oluşturmakta ve gerektikçe bu havuzdan bir bağlantıyı kullanıcının isteği doğrultusunda döndürmektedir. Bağlantı havuzu kullanımının temel gerekçesi, her seferinde bağlantı oluşturmak için gereken işlem ve bağlantı (veritabanın ağ üzerinde başka noktada olduğu durumlarda özellikle) süresini en aza indirmek için hali hazırda açık bağlantılar saklamaktır. Bu bahsedilen sınıfı İnternet üzerinden bulup, biraz değiştirirek şu anki haline getirdim. Sınıfın burada bahsedeceğim en önemli kısmı init() metodudur.

/**
* Ozellikleri yukleyip, degerleri kullanarak yeni bir nesne yaratir
*/
private void init() {
 if (dbp == null)
  dbp = DBParametersReader.readParameters();
 loadDriver(dbp);
 createPool(dbp);
}

DBParametersReader sınıfının parametre dosyasından okuduğu parametreleri yerel bir değişken olarak saklamaktadır (dbp). Daha sonra loadDriver yardımıyla kullanılacak olan sürücü yüklenmektedir. Bu sınıfın önemli bir özelliği parametre dosyasında tanımlı olan herhangi bir sürücüyü kullanabilmesidir. Bu sürücünün ilgili kütüphanesinin elbette classpathte olması gereklidir. Evet ilk defa classpath ifadesi geçti. Çoğu acemi kullanıcının bu ifadeden kaynaklı sorunlarla uğraştığını tahmin edebiliyorum. Kütüphanelerin classpathte olmasını özel olarak anlatacağım. Konumuza geri dönelim. Bu sürücü bilgisini ve parametre dosyasında diğer bilgileri kullanarak sürücü sınıfı yüklendikten sonra (loadDriver) bağlantı havuzumuz oluşturulmaktadır (createPool).

private void loadDriver(DBParameters dbp) {
 try {
  Driver driver = (Driver) Class.forName(dbp.dbDriver).newInstance();
  DriverManager.registerDriver(driver);
  log("Registered JDBC driver " + dbp.dbDriver);
 } catch (Exception e) {
  log("Can't register JDBC driver: " + dbp.dbDriver + ", Exception: " + e);
 }
}

Sürücü yükleme kodunun yaptığı işlem bağlantı almada kullanılacak olan sürücü sınıfının bulunabilmesi için sisteme kaydedilmesidir. Kaydetme işlemi tamamlandıktan sonra bağlantılar bu sürücü sınıfı yardımıyla yaratılacaktır. Bizim yazmış olduğumuz DBConnectionManager sınıfının içerisinde her ne kadar havuz oluşturabilmek için oldukça karmaşık yazılmış olsa da aşağıdaki basit kodlar yardımıyla da bağlantı alınabilmektedir. Aşağıdaki kod parçası veritabanı sürücüsünü yükleme, bağlantı yaratma, bağlantı üzerinde sorgu çalıştırma işlemlerinin oldukça kolay olduğunu gösteren bir örnektir. Örneği inceleyelim ve örnekte varolan önemli noktaları değerlendirelim:

try {
 Driver driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();
 DriverManager.registerDriver(driver);
 Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vt", "root", "tekrei");
 // veritabanina kayit ekleme
 PreparedStatement ps = con.prepareStatement("INSERT INTO Deneme (Saha) VALUES ("+System.currentTimeMillis()+")");
 ps.execute();
 //Veritabanindan kayit cekme
 ps = con.prepareStatement("SELECT * FROM Deneme");
 // cektigimiz kayitlar ResultSet nesnesi seklinde bize donuyor
 ResultSet rs = ps.executeQuery();  
 // rs nesnesinde kayitlarin hepsini dolasip
 while(rs.next()){
  // sahalari ekrana yaziyoruz
  System.out.println(rs.getString("Saha"));
 }
} catch (Exception e) {
 e.printStackTrace();
}

Sürücü yükleme Class.forName("com.mysql.jdbc.Driver").newInstance() ve DriverManager.registerDriver(driver) satırlarıyla yapılmaktadır. Bu satırların ilkinde MySQL tarafından sunulmuş olan ve sınıf yolu com.mysql.jdbc.Driver olan sürücüyü kullanacağımızı sisteme belirtmiş oluyoruz. Daha sonra sürücü hatasız bir şekilde yüklenirse (Java bildiğinizi varsayarak, hata durumunda istisna olarak yakalanacağını hatırlatmak isterim) DriverManager yardımıyla bir bağlantı yaratıyoruz (Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vt")). Bu satırda dikkat edilmesi gereken, URL dediğimiz bilginin bağlanılacak olan veritabanına dair bilgiler içeriyor olduğudur. localhost veritabanı sunucunu, 3306 bağlantı portunu ve vt veritabanın ismini belirtmektedir. Bu URL bilgileri kullanılan JDBC sürücüsüne göre değişiklik gösterecektir. JDBC sürücüsünün nasıl belgelerinde veya rehberlerinde bu bilgileri bulmak mümkündür (Bu yazının sonuna önemli olanları eklenmiştir). Ondan sonraki satırlar sırasıyla bir SQL INSERT işlemi ve SQL SELECT işlemi çalıştırılmaktadır.

Şimdiye kadar yazdıklarımla, bazı konuların ayrıntısına girmesem de, basitçe bir MySQL veritabanına bağlanmayı rahatça yapabilirsiniz. Önerim benim aşağıda bağlantısını gönderdiğim örnek projeyi inceleyerek, oradaki, DBConnectionManager, DBParameters ve DBParametersReader sınıflarını kullanarak sadece vt.properties dosyasını değiştirerek farklı veritabanları için bağlantı havuzu destekli bir yapı kullanabilirsiniz. Bütün bu sınıfların nasıl kullanıldığına dair bilgiler yorumlar şeklinde mevcut. Yapmanız gereken projenize bu sınıfları eklemek ve vt.properties dosyasını kullandığınız veritabanı, JDBC sürücüsü bilgilerine göre değiştirmek.

Gelelim eksik kalan konulara, en azından eksik bıraktığımı düşündüğüm konulara. Kolay olandan başlayalım.

Her veritabanı sürücüsü için farklı URL ve Driver bilgilerinin olduğunu söylemiştim. vt.properties dosyasında bu farklı bilgiler kullanılmalıdır. Aşağıdaki her veritabanı türü için en temel sürücü ve URL bilgilerine örnekler göreceksiniz. Bu bilgiler yetersiz gelirse ilgili JDBC sürücüsünün rehberinden veya nasıl kullanıldığını anlatan belgelerden yararlanarak edinebilirsiniz:

MySQL zaten anlatıldı ancak temel olarak sürücü için com.mysql.jdbc.Driver sınıfı ve URL olarak jdbc:mysql://localhost:3306/vt şeklinde kullanmak gerekir. Bu URL'de değiştirmeniz gereken sadece sunucu adresi (localhost), farklı bir port kullandıysanız port (3306) ve veritabanı (vt) ismidir.

(Bununla ilgili olarak MySQL connector belgesinde "If you are going to use the driver with the JDBC DriverManager, you would use "com.mysql.jdbc.Driver" as the class that implements java.sql.Driver." şeklinde bir ifade yer alır, bu sınıfı kullanmamızın nedeni budur :D Ayrıca URL ile ilgili biçimlendirme hakkında connector belgesinden yararlanılmaktadır. Bu bilgilere hangi veritabanı için olursa olsun bir google araması, olmadı ilgili sürücü belgesi yardımıyla ulaşabilirsiniz :) Aramaya inanmalısınız ;) )

Oracle:
 Sürücü = oracle.jdbc.driver.OracleDriver
 URL = jdbc:oracle:thin:@oracle:1521:orcl

(Oracle tarafından sunulan oldukça farklı seçenekler var, bu yüzden oracle'ın bu konularla ilgili belgelerini okumak ve farklı kaynakları incelemek şarttır :D )

PostgreSQL:
 Sürücü = org.postgresql.Driver
 URL = jdbc:postgresql://host:port/database

SQL Server:
 Sürücü = com.microsoft.sqlserver.jdbc.SQLServerDriver
 URL = jdbc:sqlserver://[serverName[\instanceName][:portNumber]][;property=value[;property=value]]

Java DB:
 Sürücü: org.apache.derby.jdbc.EmbeddedDriver
 URL: jdbc:derby:[propertyList]


Bu örnekler temel olarak ilgili veritabanlarına bağlanmanıza yetecektir. Ama önerim yukarıdaki çözümlere ek olarak internet üzerinde basit aramalarla ayrıntılı yazıları incelemenizdir (Örnek arama sorguları "Oracle JDBC Example" "MySQL how to use JDBC" vb.)

Bir başka önemli konu, herkesin kafasını yeterince karıştıran bir konu. CLASSPATH nedir, nasıl ayarlanır.

CLASSPATH kavramı şu noktadan çıkmaktadır. Java ile standart olarak dağıtılmayan, Java SDK'nın bir parçası olmayan kütüphanelerin sunduğu hizmetlere ve sınıflara erişebilmek için bu kütüphaneleri Java'nın çalışma ve derleme zamanında erişilebilir kılmak gerekiyor. Bunu da bu kütüphane dosyalarını (genellikle JAR oluyor bunlar) classpath içerisine yerleştirmek veya classpath ayarlarına bu kütüphanelerin bulunduğu konumu eklemek gerekiyor.

Bunu Eclipse projesi veya Netbeans projesinde yapmak kolaydır. Örneğin proje dizininiz içerisinde bir mysql.jar dosyasını projenizin kullanabilmesi için yapmanız gereken sadece Project Properties -> Java Build Path -> Libraries sekmesinde Add Jars seçeneğiyle ilgili jarı eklemektir. Netbeans içinde böyle bir menü yardımıyla rahatça yapılacaktır.


Kullanıcıları zorlayan kısmı, herhangi bir IDE kullanmadan bu kütüphanelerin "classpath"e nasıl eklendiğidir. Bunun iki yolu vardır. Birinci yol, pek tavsiye etmediğim ama işleri oldukça kolaylaştırdığı söylenen sistem classpathine bu kütüphanelerin eklenmesidir. Windowsta mesela ortam değişkenleri arasında CLASSPATH adında bir değişken ekleyip, bu değişkenin değerini ".;C:\SurucuDizini\SurucuJari.jar" şeklinde değiştirebiliriz. Böylece classpath tanımlamış oluruz. Ancak benim önerdiğim yöntem derleme ve çalıştırma yaparken bu kendimize özel classpath bilgilerini argüman olarak komutlara eklemektir.

javac -classpath c:\SurucuDizini\SurucuJari.jar AnaProgram.java

java -classpath c:\SurucuDizini\SurucuJari.jar AnaProgram

şeklinde kullanmanızdır. Elbette bu şekilde kullandığınız zaman projelerinizi ileride dağıttığınızda bu kütüphane jarlarını da beraber dağıtmanız ve kullanıcıları classpath ayarlarından kurtarmak için ilgili betik dosyalarını (linux için sh, windows için bat dosyalarını) kullanıcılara sunmanız gereklidir. Aşağıda örnek iki betik dosyasını görebilirsiniz:

calistir.sh

#!/bin/bash

java -classpath .:kumanifest.jar:./lib/derby.jar:./lib/toplink-essentials.jar:./lib/swingx.jar:./lib/nimrodlf.jar:./lib/commons-beanutils.jar:./lib/commons-collections.jar:./lib/commons-digester.jar:./lib/commons-javaflow.jar:./lib/commons-logging.jar:./lib/GUIAraclar.jar:./lib/itext.jar:./lib/jasperreports.jar:./lib/jr-bsh-compiler.jar:./lib/mysql.jar:./lib/poi.jar net.kodveus.kumanifest.MainFrame

calistir.bat

java -classpath .;kumanifest.jar;./lib/derby.jar;./lib/toplink-essentials.jar;./lib/swingx.jar;./lib/nimrodlf.jar;./lib/commons-beanutils.jar;./lib/commons-collections.jar;./lib/commons-digester.jar;./lib/commons-javaflow.jar;./lib/commons-logging.jar;./lib/GUIAraclar.jar;./lib/itext.jar;./lib/jasperreports.jar;./lib/jr-bsh-compiler.jar;./lib/mysql.jar;./lib/poi.jar net.kodveus.kumanifest.MainFrame

Gördüğünüz gibi -classpath argümanı yardımıyla kullandığım tüm kütüphaneleri, lib dizini altında kullanıcıya sunduğum kütüphaneler bunlar, classpath içerisine eklemiş oluyorum. Ve son olarak paket bilgisiyle birlikte çalıştırılacak ana sınıfı veriyorum. Ve kullanıcının classpath ayarlamasına gerek kalmadan uygulamayı çalıştırmasını sağlamış oluyorum.

Umarım buraya kadar yazdıklarım anlaşılmaktadır. 2-3 saat sürecinde ortaya çıkarılan oldukça uzun bir yazı oldu. Anlaşılmayan, hatalı olduğunu düşündüğünüz noktaları belirtirseniz, düzeltmeleri ve açıklamaları yapmaya çalışırım.

(Biterken Radiohead - Creep akustik sürüm çalıyordu)

Örnekler

(Projeyi kullanabilmek için veritabanı yaratmanız ve içerisinde projede kullanılan bir sahalı bir tabloyu eklemeniz gereklidir. Yazı kapsamında olmadığı için nasıl yapıldığı anlatılmamıştır. MySQL Workbench veya SquirrelSQL kullanarak veritabanınıza erişip bu işlemleri kolayca yapabilirsiniz.)
Kaynaklar:

Trail: JDBC(TM) Database Access
Using JDBC with MySQL, Getting Started
SQL Tutorial
The PostgreSQL JDBC Interface
SQL Server 2005 JDBC Driver Documentation
Oracle JDBC Drivers release 11.1.0.7.0 - Production README

Using Java Database Connectivity (JDBC) with Oracle
Managing the Java classpath (Windows)
How Classes are Found
Using Java DB in Desktop Applications

UNION işlemi

SQL ile çalışırken UNION ifadesi karşınıza çıkmıştır. Çok sık kullanılmasada bazı durumlarda kullanmaya zorlanabilirsiniz.

Şöyle bir örneği düşünelim(karşılaştığım bir durum); bir parametreler tablonuz (tblParametre) var. Bu tablodaki sahalar şu şekilde:
[prmKod, prmAd, grupKod, aktif]

Uygulamanızın kullandığı temel verileri ise "tblBilgi" isimli bir tabloda tutuyoruz. Ancak tblBilgi tablosu şu an aktif olmayan parametreleri de barındırıyor.

Bizden istenen belli bir gruba ait, aktif olan parametreler ile birlikte; "tblParametre" tablosunda şu an aktif olmasada, "tblBilgi" tablosunda daha önce kullanılmış olup halen geçerli olan kayıtlardaki parametrelerin tek sorgu ile getirilmesi. Bu durumda şunu yazabiliriz:

SELECT prmAd FROM tblParametre p WHERE p.grupKod='prmGrup1' AND P.aktif='E'
UNION
SELECT prmAd FROM tblParametre p WHERE p.grupKod='prmGrup1' AND
p.prmKod IN (SELECT DISTINCT(b.prmKod) FROM tblBilgi b WHERE b.gecerli = 'E')

SQL önerisi

Stored procedure(SP) yazarken, normal durumlarda IF-ENDIF, CASE gibi sorgular ile kuracağınız karar verme yapılarına seçenek olabilecek bir başka çözüm ise OR ile yapılacak mantıksal karşılaştırmalardır.

Diyelim ki okul genelinde bir devamsızlık raporu hazırlamamız gerekiyor. Raporda iki kriter var:
1. Tarih seçili ise,
2. Sınıf seçili ise,

Sınıf ve ya tarih değişkeni kullanıcı tarafından girilmezse, Bunun IF ile kontrol etmek yerine şu şekilde de karşılayabiliriz:

prmTarih ve prmSinifNo SP'ye gönderdiğimiz parametreler olsun. Seçili olmamaları halinde bunların varsayılan değerlerini "" ve -1 olarak gönderelim. Sorgumuzu şu şekilde yaparsak çözümü elde etmiş olacağız.


SELECT * FROM tbldevamsizlik td
WHERE (td.tarih = prmTarih OR prmTarih IS NULL)
AND (td.sinifNo = prmSinifNo OR prmSinifNo = -1);

***
Bu yöntemin bir de götürüsü var; performansın önemli olduğu yapılarda, ki çoğu öyledir, özellikle ana tabloda kullanılan indeksler göz önünde bulundurularak SP yazılmalıdır.

Tarih ve Sınıf numaralarının öğrenci numarası ile birlikte iki ayrı index olduğunu düşünelim:
create index tbldevamsizlik_Index1 on tbldevamsizlik (ogrenciNo, tarih);
create index tbldevamsizlik_Index2 on tbldevamsizlik (ogrenciNo, sinifNo);


Bu durumda kodu IF kontrolü ile ayırmak ve aynı kod bloğunu iki defa yazmak (kod uzasa ve tekrar etmiş olsa da) SP 'nin daha hızlı çalışmasını sağlayacaktır.
Bunun nedeni veritabanı motorunun SP için bir çalıştırma planı (execution plan) hazırlması ve bu planı SP ilk çağrıldığında kullanılan parametre/indeks eşleşmesine göre yapıp, sonraki her çağrımda aynı planı kullanması. OR yapısı kullanılırsa, indeksten faydalanma tam anlamıyla gerçekleşemeyecektir. Performans için doğru olan şu şekilde gerçekleştirimdir:


IF prmTarih IS NULL THEN
SELECT * FROM tbldevamsizlik td
WHERE (td.sinifNo = prmSinifNo);
ELSE IF prmSinifNo IS NULL THEN
SELECT * FROM tbldevamsizlik td
WHERE (td.tarih = prmTarih);
END IF;

PL/SQL - 2

PL/SQL blokları, SQL cümlelerinin daha rahat işlenebilmesini sağlarken, normal sql komutlarının da çalıştırılabilmesini sağlar.

Yakın değer fonksiyonları:

CEIL—Değerden büyük ilk tamsayı değeri verir.
FLOOR—Değerden küçük ilk tamsayı değeri verir.
TRUNC—Değerin ondalık kısmını atarak geri döndürür.
ROUND—Değeri en yakın tamsayıya yuvarlayarak getirir.

Örn:
SELECT lineno, value, ROUND(value), TRUNC(value), CEIL(value), FLOOR(value)
FROM Function-Illustrator

LineNo Value ROUND(value) TRUNC(value) CEIL(value) FLOOR(value)
---------- ---------- ------------ ------------ ----------- ------------
0 9 9 9 9 9
1 3.44 3 3 4 3
2 3.88 4 3 4 3
3 -6.27 -6 -6 -6 -7
4 -6.82 -7 -6 -6 -7
5 0 0 0 0 0
6 2.5 3 2 3 2

Not: ROUND(value,1), TRUNC(value,1) -> Bu iki fonksiyonda, ikinci bir parametre verilerek virgülden sonraki ondalık sayı duyarlılığı sağlanabilir.

lineno value ROUND(value,1) TRUNC(value,1)
---------- ---------- -------------- --------------
0 3.44 3.4 3.4


Null Değer Fonksiyonu

NVL(değer, 10) -> çekilen değerin NULL olması durumunda geriye 10 rakamını döndürür.

FROM dual
Oracle'da sql cümlesine işlem yaptırmak veya birşey hesaplatmak için from cümlesini de koymanız ve table olarak "dual" gibi bu işler için ayrılmış bir tabloyu göstermeniz gerekir. Örn:
select 2+5 from dual

PL/SQL

Oracle veritabanı, algoritmalar yazıp içerisinde SQL cümlelerini kullanabilmek için PL/SQL (Procedural Language extensions to SQL) dilini sunar.

Bu dil bize uygulama geliştirirken kullandığımız IF, CASE, WHILE gibi kontroller ile SUBSTR, LTRIM, ABS gibi fonksiyonları "Stored Procedure", "Function", "Trigger" gibi veritabanı nesnelerinde de kullanma olanağı sağlar.

PL/SQL'de ortak bir amaç için yazılmış olan "Stored Procedure" ve "Function" ları bir "Package" içerisinde toparlayabilir; sadece istediğiniz bir metodu açık(public) yapıp, ilgili uygulamanın bu metod ile erişime izin verir, diğerlerini saklayabilirsiniz.

PL/SQL'e ait birkaç özellik verecek olursak:

%TYPE
Bir sütundaki verinin tipini verir, değişken tanımlarken hata olasılığını azaltır."firmaadi" degiskeni, firmalar tablosunun firmaadi sütunun tipinde tanımlanabilir.

firmaadi firmalar.firmaadi%TYPE

"Cursor"
Bir veri bloğu çekilip,kayıtlar üzerinde satır satır işlem yapabilmemizi sağlar.

"Overloading"
Bir "Package" içerisinde aynı metod için farklı parametreler ile çağrım yapılabilmesi mümkündür.

PACKAGE BODY kontrol
IS
/* Tarih parametresi ile cagirabiliriz */
FUNCTION degerkontrol (tarih IN DATE) RETURN BOOLEAN
IS
BEGIN
RETURN tarih <= SYSDATE;
END;

/* Numara ile çağırabiliriz */
FUNCTION degerkontrol (numara IN NUMBER) RETURN BOOLEAN
IS
BEGIN
RETURN numara > 0;
END;
END;


İstisna (EXCEPTION)
İstisnaları yakalayabiliriz.


İyi bir PL/SQL için:

1. Mümkün olan en az kodu yazın
Hazır fonksiyonlar(INSTR,UPPER) ve paketleri(ROUND); önceden yazılmış ve test edilmiş kodları kullanın.
cURSOR'lerde FOR döngüsü kullanın.

2.Dinamik yapılar kullanın
Sütun veri tipi değişebilir; %TYPE ile bundan etkilenilmez
Yeni bir sütun eklenebilir; %ROWTYPE ile bundan etkilenilmez
Bir "Package" arayüzü ile veri yapılarına erişimi sınırlandırın.

3."Package" lar üzerinde yoğunlaşın
Tek başına bir SP yada Function yazmamaya çalışın. Böylece daha iyi veri arayüzleri oluşturacaksınız ve yeniden kullanılabilirliği arttırmış olacaksınız.

Notlar:
Package içinde yazılan SP ve Functionlar kullanım sırasına göre aşağıdan yukarı doğru yazılmalıdır. Kullanılacak olan SP bloğu, kullanacak(çağıracak) SP'den yukarıda yazılmalıdır.