Toplam Makale Sayısı : 268, Toplam Görsel Anlatım Sayısı : 111 (06.09.2010)
Skip Navigation Links.
Microsoft Most Valuable Professional



Bölüm 20 : JBuilder ile Database Uygulamaları - 2 23.07.2004

Geçtiğimiz hafta boyunca, JBuilder ortamında veritabanı uygulamalarının bileşenler yardımıyla kolay bir şekilde nasıl oluşturulabileceğini inceledim. Bu hafta ise, temel tablo işlemlerini kod yazmak suretiyle nasıl gerçekleştirebileceğimi araştırdım. JDBC oldukça geniş kapsama sahip bir konuydu. Hatta geniş demek yetmez tam anlamıyla bir okyanus olduğunu söyliyebilirim.

 Nasıl ki Ado.Net hakkında yazılmış kalın, devasa kitaplar var ise, JDBC içinde aynı durumun söz konusu olduğunu biliyordum. Ancak en azından elimdeki kaynaklardan faydalanarak temel bir kaç tablo işleminin nasıl gerçekleştirilebileceğinide incelem taraftarıydım. Bana gerekenler temel sql bilgisi ve JDBC' nin bu işler için hangi sınıfları kullandığıydı. Sonuç olarak aşağıdaki tarzda bir vizyon edinmeyi başarabildim. Basit bir veritabanı uygulaması için gerekli unsurlar bunlardı. Bir JDBC sürücüsü, geçerli bir bağlantı, çalışan bir sql cümleciği ve veri kümesini çekebileceğim bir bileşen.

Yapmam gereken son derece basitti. Uygulamam için geçerli bir JDBC Driver' ı yükleyecek sonra bu driver'ı kullanarak, sistemdeki odbc kaynaklarına bağlanabilecek bir Connection nesnesi oluşturacaktım. Daha sonra bu Connection nesnesini kullanan bir Statement nesnesi yaratacak ve bu nesneyi, tablodaki verileri çekmeme yardımcı olacak bir sql cümleciği ile çalıştıracaktım. Statement nesnesi, Ado.Net' teki SqlCommand nesnesine çok benziyordu. Her ikiside sql cümleciklerini çalıştırmak amacıyla kullanılabiliyorlardı. Sql cümleciğinin çalıştırılması sonucu oluşacak veri kümesini ise ResultSet sınıfından bir nesne örneğine aktaracaktım.

Bu düşünceler eşliğinde kahvemden bir yudum aldım ve uzun süre monitore bakakaldım. Nitekim ne yapacağımı biraz olsun anlamama rağmen nasıl yapacağımı henüz kestirememiştim. Elbetteki, kaynaklarım baş ucumda duruyordu. Ancak özellikle JDBC ile ilgili olan kitaplar tam anlamıyla kalın sayfa sayıları ile korkulu bir rüya gibiydiler. Kaynaklar arasında geziniyor ve en basit haliyle nasıl geliştireceğimi araştırıyordum. O kitap bu kitap derken uzun saatler sonrası bir şeyler çıkartmayı başarmıştım.

Bu araştırma yaklaşık olarak 3 gün, geceli gündüzlü sürdürdüm. Geceleri biraz uyuduğumu itiraf edeyim ama. Halen daha da tam olarak olaya vakıf olabilmiş değildim. Ancak uygulamamı nasıl geliştirebileceğimi en azından biliyordum. Hemen arkadaşımdan ödünç aldığım JBuilder Demo cd' si ile kurduğum JBuilder uygulamasını açtım. Kodlarımı JBuilder üzerinde yazacaktım. Nitekim hem tasarım ile az uğraşmak hemde JBuilder' ın intellisense özelliklerini kullanmak istiyordum. Tabi JBuilder' ın geniş yardım içeriğide işin diğer cazip tarafıydı. Öncelikle yeni bir Proje açtım, bu projeye bir Application ekledim ve temel olarak aşağıdaki gibi bir Frame oluşturdum.

Uygulamada yapmak istediklerim ilk başta, Sql sunucusunda yer alan Personel tablosundaki verileri ResultSet nesnesi içine doldurmak ve sonra bu kayıt kümesindeki satırlar arasında navigasyon tuşları yardımıyla gezinmekti. İlk olarak Doldur başlıklı button bileşenine basıldığında çalışıtırılacak olay kodlarını yazdım.

public java.sql.ResultSet rsPersonel;
public java.sql.Connection conPersonel;

void btnDoldur_actionPerformed(ActionEvent e)
{
    try
    {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        conPersonel = java.sql.DriverManager.getConnection( "jdbc:odbc:sqlBaglanti");
        java.sql.Statement sqlPersonel = conPersonel.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);
        rsPersonel = sqlPersonel.executeQuery("SELECT * FROM Personel");
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

Burada yapılan işlemler şöyleydi. İlk olarak Class sınıfının forName metodu ile, çalışacak uygulama thread' i için bir JDBC Driver' ı yükleniyordu. Ben Sql sunucuma Odbc kaynakları üzerinden bağlanmak istediğim için, JDBC' nin ODBC ile anlaşmasını sağlayacak bir driver' a ihtiyacım vardı. İşte bu amaçla JdbcOdbcDriver' ını kullandım. Artık, uygulama çalıştığında ve Doldur başlıklı butona basıldığında, ilk olarak bu uygulama için sisteme bir JdbcOdbcDriver' ı yüklenecekti. Böylece, çalışan uygulama içinden bu Driver' ı kullanarak ODBC kaynaklarına erişebilecektim. Bu erişimi sağlamak için ise tabiki geçerli bir bağlantıya sahip olmam gerekiyordu. Bunu ise, java.sql paketinde yer alan Connection sınıfı sayesinde gerçekleştirebilirdim.

java.sql.Connection conPersonel = java.sql.DriverManager.getConnection( "jdbc:odbc:sqlBaglanti");

Bu satır sayesinde, sisteme yüklediğim JDBC driver' ını kullanan bir Connection bileşeni elde etmiş oluyordum. Bu Connection bileşeni, ODBC kaynaklarında tanımladığım sqlBaglanti isimli System DSN' ini kullanacaktı. Sonraki satır ise oldukça ilginçti.

java.sql.Statement sqlPersonel = conPersonel.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE, java.sql.ResultSet.CONCUR_UPDATABLE);

Nitekim burada, Sql cümleciğini çalıştırabileceğim Ado.Net' teki SqlCommand tarzı bir bileşen tanımlanıyordu. Bunun için java.sql paketinden, Statement sınıfı kullanılıyordu. Statement bileşenini oluştururken iki parametre verdim. Bunlar ResultSet sınıfına ait değerlerdi. Amacım uygulama içinde, elde ettiğim kayıt kümesi üzerinde ileri geri hareket edebilmek olduğu için, TYPE_SCROLL_SENSITIVE değerini kullandım. Ayrıca bu değer, yapılan güncellemelerin veya değişikliklerin ResultSet üzerinde hareket ettiğimizde görünmesinide sağlamaktaydı. CONCUR_UPDATABLE değeri ise,  update işlemlerinin gerçekleştirilebileceğini belirtmekteydi. Bu değeri tam olarak anlamış değilim aslında. Sanıyorum ilerleyen zamanlarda kendisini gösterecektir.

Aslında Statement bileşenini parametresizde oluşturabilirdim. Bu durumda, kayıt kümesi varsayılan olarak ileri yönlü okumaya izin veren bir yapıda olacaktı. Dolayısıyla, geriye doğru yapılacak navigasyon hareketlerine izin vermeyecekti. Bu varsayılan değerde, TYPE_FORWARD_ONLY olarak belirtilmekteydi. ResultSet' in davranışı belirleyecek başka alan değerleride vardı. Şu an için bana gerekli olan navigasyona ve insert, update, delete gibi temel tablo işlemlerine izin veren bir ResultSet idi.

ResultSet' in elde edilmesi ise, tanımlanan Statement nesnesinin, executeQuery metodu sayesinde gerçekleştirilmekteydi. Bu metoda parametre olarak çalışmasını istediğim Sql cümleciğini vermiştim. Artık elimde Sql sunucusundaki Personel tablosunda yer alan verlileri uygulama ortamına taşıyan bir veri kümesi vardı. Şimdi uygulamayı test etme zamanı gelmişti. Hemen derleme işlemini gerçekleştirdikten sonra uygulamayı çalıştırdım ve Baglan başlıklı butona bastım. Herhangibir exception çıkmadığından, veri kümesini elde ettiğimi düşünüyordum. Şimdi ise asıl önemli olan ilk satırın verilerini, Frame' deki swing bileşenlerine nasıl dolduracağımdı. ResultSet nesnem üzerinde ileri geri hareket edebilmekteydim. İlk satıra gitmek için first, son satıra gitmek için last, önceki satır için previous ve sonraki satır için ise next metodları vardı. Önce, veri kümesindeki alan değerlerini bileşenlere yazacak ortak bir metod yazdım.

void Goster()
{
    try
    {
        this.lbID.setText(rsPersonel.getString("PersonelID"));
        this.tfAd.setText(rsPersonel.getString("PersonelAd"));
        this.tfSoyad.setText(rsPersonel.getString("PersonelSoyad"));
        this.tfUcret.setText(rsPersonel.getString("SaatUcreti"));
        this.tfSure.setText(rsPersonel.getString("CalismaSuresi"));
    }
    catch(Exception ex)
    {

    }
}

Buradaki kod satırlarında, ilgili bileşenlere setText metodu ile alan değerlerini yüklüyordum. Bunun içinde, ResultSet sınıfının getString metodu ile alan adını kullandım. Tabi almak istediğim değer integer olsaydı getInt metodunu veya tarih olsaydı getDate metodunu vb.' nı kullanabilirdim. Bu işlemlerin ardından, Doldur başlıklı butona ait kod satırlarını ve diğer navigasyon butonlarına ait olay kodlarını aşağıdaki gibi düzenledim.

public java.sql.ResultSet rsPersonel;
public java.sql.Connection conPersonel;

void btnDoldur_actionPerformed(ActionEvent e)
{
    try
    {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        java.sql.Connection conPersonel = java.sql.DriverManager.getConnection(
"jdbc:odbc:sqlBaglanti");
        java.sql.Statement sqlPersonel = conPersonel.createStatement(java.sql.ResultSet.TYPE_SCROLL_SENSITIVE,java.sql.ResultSet.CONCUR_UPDATABLE);
        rsPersonel = sqlPersonel.executeQuery("SELECT * FROM Personel");
        rsPersonel.first();
        Goster();
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

void btnIlk_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.first();
        Goster();
    }
    catch(Exception ex)
    {
    }
}

void btnOnceki_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.previous();
        Goster();
    }
    catch(Exception ex)
    {
    }
}

void btnSonraki_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.next();
        Goster();
    }
    catch(Exception ex)
    {
    }
}

void btnSon_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.last();
        Goster();
    }
    catch(Exception ex)
    {
    }
}

void this_windowClosing(WindowEvent e) {
    if(rsPersonel!=null)
    {
        try
        {
            rsPersonel.close();
            conPersonel.close();
        }
        catch(Exception hata)
        {
        }
    }
}

Uygulamamı çalıştırdığımda herşey istediğim gibiydi. Satırlar arasında gezebiliyordum.

Şimd ise istediğim, verileri güncelleyebilmek ve yeni satır veriler girebilmekti. Kaynaklarımı araştırdığımda, ResultSet sınıfının bu işlemler için kullandığı metodlar olduğunu farkettim. Bu konuları kısa bir sür inceledikten sonra Frame'e güncelleme ve ekleme işlemleri için iki button kontrolü ekledim ve aşağıdaki olay kodlarını oluşturdum.

void btngGuncelle_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.updateString("PersonelSoyad",tfSoyad.getText().toString());
        rsPersonel.updateString("PersonelAd",tfAd.getText().toString());
        java.math.BigDecimal ucret=new java.math.BigDecimal(tfUcret.getText().toString());
        rsPersonel.updateBigDecimal("SaatUcreti",ucret);
        java.math.BigDecimal sure=new java.math.BigDecimal(tfSure.getText().toString());
        rsPersonel.updateBigDecimal("CalismaSuresi",sure);
        rsPersonel.updateRow();
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

void btnEkle_actionPerformed(ActionEvent e) {
    try
    {
        rsPersonel.moveToInsertRow();
        rsPersonel.updateString("PersonelSoyad",tfSoyad.getText().toString());
        rsPersonel.updateString("PersonelAd",tfAd.getText().toString());
        java.math.BigDecimal ucret=new java.math.BigDecimal(tfUcret.getText().toString());
        rsPersonel.updateBigDecimal("SaatUcreti",ucret);
        java.math.BigDecimal sure=new java.math.BigDecimal(tfSure.getText().toString());
        rsPersonel.updateBigDecimal("CalismaSuresi",sure);
        rsPersonel.insertRow();
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage().toString());
    }
}

ResultSet bileşenin işaret ettiği veri kümesine yeni bir satır eklemek için, önce moveToInsertRow metodu ile yeni bir satır açılıyor ve cursor bu satıra konumlandırılıyordu. Daha sonra ise, updateString ve updateBigDecimal metodları ile, ilk parametre olarak verilen alanlara, ikinci parametredeki değerler yani textField bileşenlerinin içerikleri atanıyordu. Son olarak ise, insertRow metodu çağırılarak oluşturulan yeni satır ResultSet' e ekleniyordu. Güncelleme işlemindede teknik aynıydı. Sadece insertRow yerine updateRow metodu kullanılmaktaydı. Elbette buradaki güncelleme işlemleri için, yine Statement nesnesi kullanılabilirdi. Şöyleki; bu nesne ile sql cümlecikleri çalıştırılabildiğine göre insert ve update sql cümleciklerini çalışıtırarakta ekleme ve güncelleme işlemlerini yaptırabilirdim.

JDBC ile ilgili konular gerçekten saymak ile bitmiyor ve bitecek gibide değil. Bu konu ile ilgili olarak yeni bir 24 kahve molası yapsam az geleceğine inanıyorum. Ancak araştırmaya devam etmekte elbetteki büyük fayda var. Yorucu bir hafta sonrası JDBC ile çok fazla şey yapamasamda en azından biraz kulak dolgunluğu yakalamış durumdayım. Ancak tabiki yeterli değil. Bakalım gelecek kahve molalarında Java okyanusunun hangi derin sularında, ne yükseklikteki çalkantılı dalgalarla boğuşuyor olacağım.

Burak Selim ŞENYURT

selim@bsenyurt.com

Tasarlayan : Tasarım Fukarası Burak Selim Şenyurt (2008)