Skip to content

6. API ile veritabanı yönetimi JDBC

6.1. Genel Bilgiler

Piyasada çok sayıda veritabanı bulunmaktadır. MS Windows altında veritabanlarına erişimi standartlaştırmak amacıyla Microsoft, ODBC (Open DataBase Connectivity) adlı bir arayüz geliştirmiştir. Bu katman, her bir veritabanının kendine özgü özelliklerini standart bir arayüz altında gizler. Windows ortamında, veritabanlarına erişimi kolaylaştıran çok sayıda sürücü bulunmaktadır. Örneğin, bir Win95 makinesinde yüklü olan sürücülerin listesi şöyledir:

Image

Bu sürücülere dayanan bir uygulama, yeniden yazmaya gerek kalmadan yukarıdaki herhangi bir veritabanını kullanabilir.

Image

Java uygulamalarının da ODBC arayüzünden yararlanabilmesi için, Sun, Java uygulaması ile ODBC arayüzü arasına yerleştirilecek olan JDBC (Java DataBase Bağlantısı) arayüzünü geliştirmiştir:

Image

6.2. Veritabanı işletiminde önemli adımlar

6.2.1. Giriş

JAVA arayüzüne sahip bir veritabanını kullanan bir JDBC uygulamasında genellikle aşağıdaki adımlar bulunur:

  1. Veritabanına bağlanma
  2. Veritabanına SQL sorgularının gönderilmesi
  3. Bu sorguların sonuçlarının alınması ve işlenmesi
  4. Bağlantının kapatılması
  1. ve 3. adımlar tekrar tekrar gerçekleştirilir; bağlantı kapatma işlemi ise veritabanının işlenmesi tamamlandığında gerçekleşir. Bu, etkileşimli bir şekilde veritabanı kullanmışsanız aşina olabileceğiniz nispeten klasik bir şemadır. Bir örnek üzerinden bu adımların her birini ayrıntılı olarak inceleyeceğiz. ACCESS adlı ve aşağıdaki yapıya sahip bir veritabanını ele alalım:
ad
tür
code
4 karakterlik ürün kodu
nom
adı (karakter dizisi)
prix
fiyatı (gerçek)
stock_actu
mevcut stoğu (tamsayı)
stock_mini
ürünün yeniden stoklanması gereken minimum stok seviyesi (tamsayı)

Bu ACCESS veritabanı, ODBC veritabanı yöneticisinde "kullanıcı" veri kaynağı olarak tanımlanmıştır:

Image

Image

Özellikleri, Configurer düğmesi kullanılarak şu şekilde belirtilmiştir:

Image

Bu yapılandırma temel olarak, ARTICLES veritabanına, bu veritabanına karşılık gelen articles.mdb Access dosyasını eşleştirmekten ibarettir. Bu işlem tamamlandığında, ARTICLES veritabanına, ODBC arayüzünü kullanan uygulamalar erişebilir.

6.2.2. Bağlantı aşaması

Bir veritabanını kullanmak için, bir Java uygulamasının önce bir bağlantı aşaması gerçekleştirmesi gerekir. Bu, aşağıdaki sınıf yöntemiyle yapılır:

Connection DriverManager.getConnection(String URL, String id, String mdp)

ile

DriverManager: uygulama için kullanılabilir sürücülerin listesini barındıran Java sınıfı

Connection: uygulama ile veritabanı arasında bir bağlantı kuran Java sınıfı; bu bağlantı sayesinde uygulama, SQL sorgularını veritabanına iletir ve sonuçları alır

URL: veritabanını tanımlayan ad. Bu ad, İnternet’teki URL’lere benzerdir. Bu nedenle URL sınıfının bir parçasıdır. Ancak burada İnternet’in hiçbir rolü yoktur. URL şu biçimdedir:

jdbc:nom_du_pilote:nom_de_la_source;param=val1;param2=val2

Yalnızca ODBC sürücülerini kullanacağımız örneklerimizde, sürücünün adı odbc'dir. URL'in üçüncü kısmı, kaynak adından ve olası parametrelerden oluşur. Örneklerimizde, bunlar sistem tarafından tanınan ODBC kaynakları olacaktır. Dolayısıyla, daha önce tanımlanan Articles veri kaynağının URL değeri şu şekilde olacaktır:

jdbc:odbc:Makaleler

id: Kullanıcı kimliği (login)

mdp: Kullanıcı şifresi (password)

Özetle, program bir veritabanına bağlanır:

  • bir kullanıcı kimliği (id, mdp) ile tanımlanan
  • bir kullanıcı kimliği (id, mdp) ile

Bu üç parametre doğruysa ve Java uygulamasının belirtilen veritabanına bağlanmasını sağlayabilecek sürücü mevcutsa, Java uygulaması ile veritabanı arasında bir bağlantı kurulur. Bu bağlantı, program için DriverManager sınıfı tarafından döndürülen Connection türündeki nesne ile somutlaşır. Bu bağlantı çeşitli nedenlerle başarısız olabileceğinden, bir istisna tetikleyebilir. Dolayısıyla şu şekilde yazılır:


    Connection connexion=null;
    URL base=...;
    String id=...;
    String mdp=...;
try{
        connexion=DriverManager.getConnection(base,id,mdp);
} catch (Exception e){
        // istisnayı işleme
}

Bir veritabanına bağlanabilmek için uygun sürücünün bulunması gerekir. Örneklerimizde, istenen veritabanını yönetebilen ODBC sürücüsü kullanılacaktır. Bu sürücünün, makinede bulunan ODBC sürücü listesinde mevcut olması gerekiyorsa, sürücüyle arayüz oluşturacak JAVA sınıfının da mevcut olması gerekir. Bunun için uygulama, gerekli olan sınıfı şu şekilde talep edecektir:

    Class.forName(String nomClasse)

Class sınıfı, JDBC arayüzüyle hiçbir şekilde bağlantılı değildir. Bu, sınıf yönetimine yönelik genel bir sınıftır. forName adlı statik yöntemi, bir sınıfı dinamik olarak yüklemeye ve böylece o sınıfın özniteliklerinden ve statik yöntemlerinden yararlanmaya olanak tanır. ODBC ve MS Windows sürücüleriyle arayüz oluşturan sınıfın adı “sun.jdbc.odbc.JdbcOdbcDriver”’tir. Dolayısıyla şu şekilde yazılır (yöntem bir istisna oluşturabilir):

try{
    Class.forName(« sun.jdbc.odbc.JdbcOdbcDriver ») ;
} catch (Exception e){
    // istisna işleme (sınıf mevcut değil)
}

JDBC arayüzü için gerekli sınıflar, java.sql paketinde bulunur. Dolayısıyla programın başına şunu yazacağız:

    import java.sql.*;

Aşağıda, bir veritabanına bağlanmayı sağlayan bir program yer almaktadır:

import java.sql.*;
import java.io.*;

// çağrı: pg PILOTE URL UID MDP
// JDBC sınıfı aracılığıyla URL veritabanına bağlanıyor PILOTE
// UID kullanıcısı, MDP şifresiyle tanımlanır

public class connexion1{
    static String syntaxe="pg PILOTE URL UID MDP";

    public static void main(String arg[]){
        // argüman sayısının doğrulanması
        if(arg.length<2 || arg.length>4)
            erreur(syntaxe,1);
        // veritabanına bağlanma
        Connection connect=null;
        String uid="";
        String mdp="";
        if(arg.length>=3) uid=arg[2];
        if(arg.length==4) mdp=arg[3];        
        try{
            Class.forName(arg[0]);
            connect=DriverManager.getConnection(arg[1],uid,mdp);
            System.out.println("Connexion avec la base " + arg[1] + " établie");
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // veritabanının kapatılması
        try{
            connect.close();
            System.out.println("Base " + arg[1] + " fermée");
        } catch (Exception e){}
    }// ana sayfa

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// sınıf    

İşte bir çalıştırma örneği:

E:\data\java\jdbc\0>java connexion1 sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles
Connexion avec la base jdbc:odbc:articles établie
Base jdbc:odbc:articles fermée

6.2.3. Veritabanına sorgu gönderme

JDBC arayüzü, Java uygulamasına bağlı veritabanına SQL sorgularının gönderilmesini ve bu sorguların sonuçlarının işlenmesini sağlar. SQL dili (Structured Query Language), ilişkisel veritabanları için standartlaştırılmış bir sorgu dilidir. Bu dilde çeşitli sorgu türleri bulunur:

  • veritabanı sorgulama sorguları (SELECT)
  • veritabanı güncelleme sorguları (INSERT, DELETE, UPDATE)
  • tablo oluşturma/silme sorguları (CREATE, DELETE)

Burada okuyucunun SQL dilinin temellerini bildiği varsayılmaktadır.

6.2.3.1. Statement sınıfı

Bir veritabanına herhangi bir SQL sorgusu göndermek için, Java uygulamasının bir Statement türü nesnesine sahip olması gerekir. Bu nesne, diğer şeylerin yanı sıra sorgunun metnini de depolar. Bu nesne, mutlaka mevcut bağlantıya bağlıdır. Dolayısıyla, SQL sorgularını göndermek için gerekli olan Statement nesnelerini oluşturmaya olanak tanıyan, kurulan bağlantının bir yöntemidir. connexion, veritabanıyla bağlantıyı temsil eden nesne ise, bir Statement nesnesi şu şekilde elde edilir:

    Statement requete=connexion.CreateStatement();

Statement nesnesi elde edildikten sonra, SQL sorguları oluşturulabilir. Bu işlem, sorgunun veritabanından bilgi alma sorgusu mu yoksa güncelleme sorgusu mu olduğuna göre farklı şekilde gerçekleştirilir.

6.2.3.2. Veritabanından sorgu istemi gönderme

Bir sorgu isteği genellikle şu türdedir:

    select col1, col2,... from table1, table2,...
    where condition
    order by expression
    ...

Yalnızca ilk satırdaki anahtar kelimeler zorunludur, diğerleri isteğe bağlıdır. Burada gösterilmeyen başka anahtar kelimeler de mevcuttur.

  1. "from" anahtar sözcüğünün ardından gelen tüm tablolarla bir birleştirme işlemi yapılır
  2. Yalnızca "select" anahtar sözcüğünün ardından gelen sütunlar tutulur
  3. Yalnızca "where" anahtar sözcüğündeki koşulu karşılayan satırlar tutulur
  4. "order by" anahtar sözcüğündeki ifadeye göre sıralanan satırlar, sorgunun sonucunu oluşturur.

select sorgusunun sonucu bir tablodur. Yukarıdaki ARTICLES tablosunu ele alalım ve mevcut stoğu minimum eşik değerinin altında olan ürünlerin adlarını almak istiyorsak, şu komutu yazacağız: select nom from articles where stock_actu<stock_mini. Bunları isimlerine göre alfabetik sırayla almak istersek, şu komutu yazacağız: select isim from ürünler where stock_actu<stock_mini order by isim

Bu tür bir sorguyu çalıştırmak için, Statement sınıfı executeQuery yöntemini sunar:

    ResultSet executeQuery(String requête)

burada requête, gönderilecek SELECT sorgusunun metnidir.

Dolayısıyla, eğer

  • connexion, veritabanı bağlantısını temsil eden nesne ise
  • Statement s=connexion.createStatement() ifadesi, SQL sorgularının gönderilmesi için gerekli olan Statement nesnesini oluşturur
  • ResultSet rs=s.executeQuery(" select nom from articles where stock_actu<stock_mini ») komutu, bir select sorgusunu yürütür ve sorgunun sonuç satırlarını bir ResultSet türündeki nesneye atar.

6.2.3.3. ResultSet sınıfı: bir select sorgusunun sonucu

ResultSet türündeki bir nesne, bir tabloyu, yani satır ve sütunlardan oluşan bir kümeyi temsil eder. Herhangi bir anda, tablodaki yalnızca bir satıra, yani “geçerli satır” olarak adlandırılan satıra erişilebilir. ResultSet nesnesinin ilk oluşturulduğu sırada, ResultSet boş değilse geçerli satır 1 numaralı satırdır. Bir sonraki satıra geçmek için, ResultSet sınıfında next yöntemi bulunur:

    boolean next()

Bu yöntem, ResultSet'in bir sonraki satırına geçmeye çalışır ve başarılı olursa true değerini, aksi takdirde false değerini döndürür. Başarılı olması durumunda, bir sonraki satır yeni geçerli satır olur. Önceki satır kaybolur ve geri dönüp onu kurtarmak mümkün olmaz. ResultSet tablosunda col1, col2, ... sütunları bulunur. Geçerli satırdaki çeşitli alanları işlemek için aşağıdaki yöntemler kullanılabilir:

Type getType("coli") 

akım satırındaki “coli” alanını almak için kullanılır. Type, coli alanının türünü belirtir. Tüm alanlarda getString yöntemi sıklıkla kullanılır; bu, alanın içeriğini bir karakter dizisi olarak elde etmeyi sağlar. Daha sonra gerekirse dönüştürme işlemi yapılır. Sütun adı bilinmiyorsa, şu yöntemler kullanılabilir:

Type getType(i) 

kullanılabilir; burada i, istenen sütunun indeksidir (i>=1).

6.2.3.4. İlk örnek

İşte daha önce oluşturulan ARTICLES veritabanının içeriğini görüntüleyen bir program:

import java.sql.*;
import java.io.*;

// bir sistem veritabanının içeriğini görüntüler ARTICLES

public class articles1{

    static final String DB="ARTICLES";        // kullanılacak veritabanı

    public static void main(String arg[]){

        Connection connect=null;        // veritabanına bağlantı
        Statement S=null;                // sorguların gönderileceği nesne
        ResultSet RS=null;            // sorgu sonuç tablosu
        try{
            // veritabanına bağlantı
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            // Statement nesnesinin oluşturulması
            S=connect.createStatement();
            // select sorgusunun yürütülmesi
            RS=S.executeQuery("select * from " + DB);
            // sonuç tablosunun işlenmesi
            while(RS.next()){                // işlenecek satır olduğu sürece
                // ekrana görüntülenir
                System.out.println(RS.getString("code")+","+
                    RS.getString("nom")+","+
                    RS.getString("prix")+","+
                    RS.getString("stock_actu")+","+
                    RS.getString("stock_mini"));
            }// sonraki satır
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // veritabanının kapatılması
        try{
            connect.close();
            System.out.println("Base " + DB + " fermée");
        } catch (Exception e){}
    }// el

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// sınıf    

Elde edilen sonuçlar şunlardır:

Connexion avec la base ARTICLES établie
a300,vélo,1202,30,2
d600,arc,5000,10,2
d800,canoé,1502,12,6
x123,fusil,3000,10,2
s345,skis nautiques,1800,3,2
f450,essai3,3,3,3
f807,cachalot,200000,0,0
z400,léopard,500000,1,1
g457,panthère,800000,1,1
Base ARTICLES fermée

6.2.3.5. ResultSetMetadata sınıfı

Önceki örnekte, ResultSet'in sütun adları biliniyor. Bunlar bilinmiyorsa, getType(nom_colonne) yöntemi kullanılamaz. Bunun yerine getType(sütun numarası) kullanılmalıdır. Ancak, tüm sütunları elde etmek için, elde edilen ResultSet'in kaç sütun içerdiğini bilmemiz gerekir. ResultSet sınıfı bize bu bilgiyi vermez. Bu bilgiyi bize ResultSetMetaData sınıfı sağlar. Daha genel olarak, bu sınıf bize tablonun yapısı, yani sütunlarının niteliği hakkında bilgi verir.

Bir ResultSet'in yapısı hakkındaki bilgilere erişmek için öncelikle bir ResultSetMetaData nesnesi oluşturmamız gerekir. RS bir ResultSet ise, ilişkili ResultSetMetaData şu şekilde elde edilir:

    RS.getMetaData()

ResultSetMetaData sınıfında iki yararlı yöntem dikkat çekmektedir:

  1. getColumnCount() yöntemi, ResultSet'in sütun sayısını verir
  2. String getColumnLabel(int i) işlevi, ResultSet nesnesindeki i numaralı sütunun adını verir (i>=1)

6.2.3.6. İkinci bir örnek

Önceki program, ARTICLES veritabanının içeriğini görüntülüyordu. Burada, kullanıcının klavyeden girdiği tüm SQL ve Select sorgularını ARTICLES veritabanında çalıştıran bir program yazacağız.

import java.sql.*;
import java.io.*;

// bir sistem tabanının içeriğini görüntüler ARTICLES

public class sql1{

    static final String DB="ARTICLES";        // kullanılacak veritabanı

    public static void main(String arg[]){

        Connection connect=null;        // veritabanına bağlantı
        Statement S=null;                // sorguların gönderileceği nesne
        ResultSet RS=null;            // sorgu sonuç tablosu
        String select;                    // SQL select sorgusunun metni
        int nbColonnes;                // ResultSet'in sütun sayısı

        // klavye giriş akışının oluşturulması
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            // veritabanına bağlanma
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            // Statement nesnesinin oluşturulması
            S=connect.createStatement();
            // klavyeden girilen SQL sorgularının yürütülmesi döngüsü
            System.out.print("Requête : ");
            select=in.readLine();
            while(!select.equals("fin")){
                // sorgunun yürütülmesi
                RS=S.executeQuery(select);
                // sütun sayısı
                nbColonnes=RS.getMetaData().getColumnCount();
                // sonuç tablosunun işlenmesi
                System.out.println("Résultats obtenus\n\n");
                while(RS.next()){                // işlenecek satır olduğu sürece
                    // ekrana görüntülenir
                    for(int i=1;i<nbColonnes;i++)
                        System.out.print(RS.getString(i)+",");
                    System.out.println(RS.getString(nbColonnes));
                }// sonraki satır
                // sonraki sorgu
                System.out.print("Requête : ");
                select=in.readLine();                
            }// while
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // veritabanı ve giriş akışının kapatılması
        try{
            connect.close();
            System.out.println("Base " + DB + " fermée");
            in.close();
        } catch (Exception e){}
    }// main

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// sınıf    

İşte elde edilen bazı sonuçlar:

Connexion avec la base ARTICLES établie
Requête : select * from articles order by prix desc
Résultats obtenus


g457,panthère,800000,1,1
z400,léopard,500000,1,1
f807,cachalot,200000,0,0
d600,arc,5000,10,2
x123,fusil,3000,10,2
s345,skis nautiques,1800,3,2
d800,canoé,1502,12,6
a300,vélo,1202,30,2
f450,essai3,3,3,3

Requête : select nom, prix from articles where prix >10000 order by prix desc
Résultats obtenus


panthère,800000
léopard,500000
cachalot,200000

6.2.3.7. Veritabanı güncelleme isteği gönderme

Statement türündeki bir nesne, SQL isteklerini depolamaya olanak tanır. Bu nesnenin SQL güncelleme isteklerini göndermek için kullandığı yöntem (INSERT, UPDATE, DELETE) için kullandığı yöntem, daha önce incelenen executeQuery yöntemi değil, executeUpdate yöntemidir:

    int executeUpdate(String requête)

Aradaki fark sonuçta ortaya çıkıyor: executeQuery, sonuç tablosunu (ResultSet) döndürürken, executeUpdate, güncelleme işleminden etkilenen satır sayısını döndürür.

6.2.3.8. Üçüncü bir örnek

Önceki programı alıp üzerinde küçük bir değişiklik yapıyoruz: klavyeden girilen sorgular artık ARTICLES veritabanını güncelleyen sorgulardır.

import java.sql.*;
import java.io.*;

// bir sistem veritabanının içeriğini görüntüler ARTICLES

public class sql2{

    static final String DB="ARTICLES";    // kullanılacak veritabanı

    public static void main(String arg[]){

        Connection connect=null;        // veritabanına bağlantı
        Statement S=null;                // sorguların gönderileceği nesne
        ResultSet RS=null;            // sorgu sonuç tablosu
        String sqlUpdate;                // SQL güncelleme sorgusunun metni
        int nbLignes;                    // güncellemeden etkilenen satır sayısı

        // klavye giriş akışının oluşturulması
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            // veritabanına bağlanma
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            connect=DriverManager.getConnection("jdbc:odbc:"+DB,"","");
            System.out.println("Connexion avec la base " + DB + " établie");
            // Statement nesnesinin oluşturulması
            S=connect.createStatement();
            // klavyeden girilen SQL sorgularının yürütülmesi döngüsü
            System.out.print("Requête : ");
            sqlUpdate=in.readLine();
            while(!sqlUpdate.equals("fin")){
                // sorgunun yürütülmesi
                nbLignes=S.executeUpdate(sqlUpdate);
                // izleme
                System.out.println(nbLignes + " ligne(s) ont été mises à jour");
                // sonraki sorgu
                System.out.print("Requête : ");
                sqlUpdate=in.readLine();                
            }// while
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // veritabanı ve giriş akışının kapatılması
        try{
            // veritabanıyla ilişkili kaynakların serbest bırakılması
            RS.close();
            S.close();
            connect.close();
            System.out.println("Base " + DB + " fermée");
            // klavye akışını kapatma
            in.close();
        } catch (Exception e){}
    }// el

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// sınıf    

sql1 ve sql2 programlarının çeşitli çalıştırmalarının sonucu şöyledir:

ARTICLES veritabanındaki satırların listesi:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus


vélo,30
arc,10
canoé,12
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

Bazı satırları değiştiriyoruz:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : update articles set stock_actu=stock_actu+1 where stock_actu>10
2 ligne(s) ont été mises à jour

Doğrulama:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus

vélo,31
arc,10
canoé,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

Bir satır eklenir:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',200,20,10)
1 ligne(s) ont été mises à jour

Doğrulama:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requ_te : select nom,stock_actu from articles
Résultats obtenus

vélo,31
arc,10
canoé,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1
nouveau,20

Bir satır siliniyor:


E:\data\java\jdbc\0>java sql2
Connexion avec la base ARTICLES établie
Requête : delete from articles where code='x400'
1 ligne(s) ont été mises à jour
Requête : fin

Doğrulama:


E:\data\java\jdbc\0>java sql1
Connexion avec la base ARTICLES établie
Requête : select nom,stock_actu from articles
Résultats obtenus


vélo,31
arc,10
cano_,13
fusil,10
skis nautiques,3
essai3,3
cachalot,0
léopard,1
panthère,1

6.2.3.9. Herhangi bir SQL isteği gönderin

SQL isteklerini göndermek için gerekli olan Statement nesnesi, her türlü SQL isteğini yürütebilen bir execute yöntemine sahiptir:

    boolean execute(String requête)

İstek bir ResultSet (executeQuery) değerini döndürdüyse, döndürülen sonuç true boole değeridir; bir sayı döndürdüyse (executeUpdate) döndürdüyse false olur. Elde edilen ResultSet değeri, getResultSet yöntemi ile, güncellenen satır sayısı ise getUpdateCount yöntemi ile alınabilir. Böylece şu şekilde yazılır:


Statement S=...;
ResultSet RS=...;
int nbLignes;
String requête=...;
// sorgu yürütme SQL
if (S.execute(requête)){
    // bir sonuç kümesi var
    RS=S.getResultSet();
    // ResultSet'in değerlendirilmesi
    ...
} else {
    // bu bir güncelleme sorgusuydu
    nbLignes=S.getUpdateCount();
    ...
}

6.2.3.10. Dördüncü örnek

sql1 ve sql2 programlarının mantığını, artık klavyeden girilen tüm SQL sorgularını çalıştırabilen sql3 programında yeniden ele alıyoruz. Programı daha genel hale getirmek için, işlenecek veritabanının özellikleri programa parametre olarak aktarılır.

import java.sql.*;
import java.io.*;

// çağrı: pg PILOTE URL UID MDP
//, JDBC sınıfı aracılığıyla URL veritabanına bağlanıyor PILOTE
// UID kullanıcısı, MDP şifresiyle tanımlanır

public class sql3{

    static String syntaxe="pg PILOTE URL UID MDP";

    public static void main(String arg[]){



        // argüman sayısının doğrulanması
        if(arg.length<2 || arg.length>4)
            erreur(syntaxe,1);

        // bağlantı parametrelerinin başlatılması
        Connection connect=null;
        String uid="";
        String mdp="";
        if(arg.length>=3) uid=arg[2];
        if(arg.length==4) mdp=arg[3];        

        // diğer veriler
        Statement S=null;                        // istek gönderme nesnesi
        ResultSet RS=null;                    // sorgu sonucunun tablosu
        String sqlText;                            // çalıştırılacak SQL sorgusunun metni
        int nbLignes;                                // güncellemeden etkilenen satır sayısı
        int nbColonnes;                            // ResultSet'in sütun sayısı

        // klavye giriş akışının oluşturulması
        BufferedReader in=null;
        try{
            in=new BufferedReader(new InputStreamReader(System.in));
        } catch(Exception e){
            erreur("erreur lors de l'ouverture du flux clavier ("+e+")",3);
        }
        try{
            // veritabanına bağlanma
            Class.forName(arg[0]);
            connect=DriverManager.getConnection(arg[1],uid,mdp);
            System.out.println("Connexion avec la base " + arg[1] + " établie");
            // Statement nesnesinin oluşturulması
            S=connect.createStatement();
            // klavyeden girilen SQL sorgularının yürütülmesi döngüsü
            System.out.print("Requête : ");
            sqlText=in.readLine();
            while(!sqlText.equals("fin")){
                // sorgunun yürütülmesi
                try{
                    if(S.execute(sqlText)){
                        // ResultSet elde edildi - bu sonuç işleniyor
                        RS=S.getResultSet();
                        // sütun sayısı
                        nbColonnes=RS.getMetaData().getColumnCount();
                        // sonuç tablosunun işlenmesi
                        System.out.println("\nRésultats obtenus\n-----------------\n");
                        while(RS.next()){                // işlenecek satır olduğu sürece
                            // ekrana görüntüleniyor
                            for(int i=1;i<nbColonnes;i++)
                                System.out.print(RS.getString(i)+",");
                            System.out.println(RS.getString(nbColonnes));
                        }// ResultSet'in bir sonraki satırı
                    } else {
                        // bu bir güncelleme isteğiydi
                        nbLignes=S.getUpdateCount();
                        // takip
                        System.out.println(nbLignes + " ligne(s) ont été mises à jour");
                    }//if
                } catch (Exception e){
                    System.out.println("Erreur " +e);
                }
                // sonraki istek
                System.out.print("\nNouvelle Requête : ");
                sqlText=in.readLine();                
            }// while
        } catch (Exception e){
            erreur("Erreur " + e,2);
        }
        // veritabanı ve giriş akışının kapatılması
        try{
            // veritabanıyla ilişkili kaynaklar serbest bırakılır
            RS.close();
            S.close();
            connect.close();
            System.out.println("Base " + arg[1] + " fermée");
            // klavye akışının kapatılması
            in.close();
        } catch (Exception e){}
    }// main

    public static void erreur(String msg, int exitCode){
        System.err.println(msg);
        System.exit(exitCode);
    }
}// sınıf    

Aşağıdaki sorgu dosyası oluşturulur:

select * from articles
update articles set stock_mini=stock_mini+5 where stock_mini<5
select nom,stock_mini from articles
insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',100,20,10)
select * from articles
delete from articles where code='x400'
select * from articles
fin

Program şu şekilde çalıştırılır:

E:\data\java\jdbc\0>java sql3 sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles <requetes >results

Dolayısıyla program, girdilerini requetes dosyasından alır ve çıktısını results dosyasına kaydeder. Elde edilen sonuçlar şunlardır:

Connexion avec la base jdbc:odbc:articles établie

Requête : (requete 1 du fichier des requetes : select * from articles)
Résultats obtenus
-----------------

a300,vélo,1202,31,3
d600,arc,5000,10,3
d800,canoé,1502,13,7
x123,fusil,3000,10,3
s345,skis nautiques,1800,3,3
f450,essai3,3,3,4
f807,cachalot,200000,0,1
z400,léopard,500000,1,2
g457,panthère,800000,1,2

Nouvelle Requête : (requete 2 du fichier des requetes : update articles set stock_mini=stock_mini+5 where stock_mini<5)

8 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 3 du fichier des requetes : select nom,stock_mini from articles)

Résultats obtenus
-----------------

vélo,8
arc,8
canoé,7
fusil,8
skis nautiques,8
essai3,9
cachalot,6
léopard,7
panthère,7

Nouvelle Requête : (requete 4 du fichier des requetes : insert into articles (code,nom,prix,stock_actu,stock_mini) values ('x400','nouveau',100,20,10))

1 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 5 du fichier des requetes : select * from articles)

Résultats obtenus
-----------------

a300,vélo,1202,31,8
d600,arc,5000,10,8
d800,canoé,1502,13,7
x123,fusil,3000,10,8
s345,skis nautiques,1800,3,8
f450,essai3,3,3,9
f807,cachalot,200000,0,6
z400,léopard,500000,1,7
g457,panthère,800000,1,7
x400,nouveau,100,20,10

Nouvelle Requête : (requete 6 du fichier des requêtes : delete from articles where code='x400')


1 ligne(s) ont é mises à jour

Nouvelle Requête : (requete 7 du fichier des requêtes : select * from articles)

Résultats obtenus
-----------------

a300,vélo,1202,31,8
d600,arc,5000,10,8
d800,canoé,1502,13,7
x123,fusil,3000,10,8
s345,skis nautiques,1800,3,8
f450,essai3,3,3,9
f807,cachalot,200000,0,6
z400,léopard,500000,1,7
g457,panthère,800000,1,7

6.3. IMPOTS bir veritabanı ile

Vergi hesaplama konusunu en son ele aldığımızda, bir grafik kullanıcı arayüzü kullanmıştık ve veriler bir dosyada depolanmıştı. Bu sürümü, verilerin artık bir ODBC-MySQL veritabanında olduğunu varsayarak yeniden ele alıyoruz. MySQL, Windows ve Linux dahil olmak üzere çeşitli platformlarda kullanılabilen, kamu malı olan bir SGBD dosyasıdır. Bu SGBD ile, içinde impots adlı tek bir tablo bulunan dbimpots adlı bir veritabanı oluşturulmuştur. Veritabanına erişim, burada admimpots/mdpimpots kullanıcı adı ve şifre ile kontrol edilmektedir. Ekran görüntüsü, dbimpots veritabanının MySQL ile nasıl kullanılacağını göstermektedir:


C:\Program Files\EasyPHP\mysql\bin>mysql -u admimpots -p
Enter password: *********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 18 to server version: 3.23.49-max-nt

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use dbimpots;
Database changed

mysql> show tables;
+--------------------+
| Tables_in_dbimpots |
+--------------------+
| impots             |
+--------------------+
1 row in set (0.00 sec)

mysql> describe impots;
+---------+--------+------+-----+---------+-------+
| Field   | Type   | Null | Key | Default | Extra |
+---------+--------+------+-----+---------+-------+
| limites | double | YES  |     | NULL    |       |
| coeffR  | double | YES  |     | NULL    |       |
| coeffN  | double | YES  |     | NULL    |       |
+---------+--------+------+-----+---------+-------+
3 rows in set (0.02 sec)

mysql> select * from impots;
+---------+--------+---------+
| limites | coeffR | coeffN  |
+---------+--------+---------+
|   12620 |      0 |       0 |
|   13190 |   0.05 |     631 |
|   15640 |    0.1 |  1290.5 |
|   24740 |   0.15 |  2072.5 |
|   31810 |    0.2 |  3309.5 |
|   39970 |   0.25 |    4900 |
|   48360 |    0.3 |    6898 |
|   55790 |   0.35 |  9316.5 |
|   92970 |    0.4 |   12106 |
|  127860 |   0.45 |   16754 |
|  151250 |    0.5 | 23147.5 |
|  172040 |   0.55 |   30710 |
|  195000 |    0.6 |   39312 |
|       0 |   0.65 |   49062 |
+---------+--------+---------+
14 rows in set (0.00 sec)

mysql>quit

Uygulamanın grafik arayüzü şu şekildedir:

Image

Grafik kullanıcı arayüzünde bazı değişiklikler yapılmıştır:

no
tür
ad
rol
1
JTextField
txtConnexion
veritabanı bağlantı dizesi ODBC
2
JScrollPane
JScrollPane1
textarea için konteyner 3
3
JTextArea
txtStatus
durum mesajlarını, özellikle hata mesajlarını görüntüler

(1) numaralı alana girilen bağlantı dizesi şu şekildedir: DSN;login;şifre;

DSN
DSN adındaki veri kaynağının adı ODBC

login
veritabanında okuma hakkına sahip bir kullanıcının kimliği

motdepasse
şifresi

dbimpots veritabanı, MySQL ile manuel olarak oluşturulmuştur. Bu veritabanı, aşağıdaki şekilde ODBC veri kaynağına dönüştürülür:

  • 32 bitlik ODBC veri kaynağı yöneticisini başlatın

Image

  • [Add] düğmesini kullanarak yeni bir veri kaynağı ODBC eklenir

Image

  • MySQL sürücüsünü seçip [Terminer]'i yapıyoruz

Image

  • MySQL sürücüsü bazı bilgiler ister:
1
ODBC veri kaynağına verilecek DSN adı - herhangi bir isim olabilir
2
SGBD MySQL'in çalıştığı makine - burada QZXX2HTMLP002447ZQX. Veritabanının uzak bir veritabanı olabileceğini belirtmek ilginçtir. ODBC veri kaynağını kullanan yerel uygulamalar bunun farkına varmaz. Özellikle Java uygulamamızda durum böyle olur.
3
kullanılacak MySQL veritabanı. MySQL, ilişkilerle birbirine bağlanmış tablo kümeleri olan ilişkisel veritabanlarını yöneten bir SGBD'tir. Burada, yönetilen veritabanının adı verilir.
4
Bu veritabanına erişim hakkı olan bir kullanıcının adı
5
kullanıcı şifresi

ODBC veri kaynağı tanımlandıktan sonra programımızı test edebiliriz:

 

Veritabanı içermeyen grafik sürümüne kıyasla değiştirilen kodu inceleyelim. Şimdiye kadar kullanılan impots sınıfının kodunu hatırlayalım:

// "impots" sınıfının oluşturulması

public class impots{

    // vergi hesaplaması için gerekli veriler
     // dış bir kaynaktan gelir

    private double[] limites, coeffR, coeffN;

     // oluşturucu
    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception{
         // 3 tablonun da aynı boyutta olup olmadığı kontrol edilir
        boolean OK=LIMITES.length==COEFFR.length && LIMITES.length==COEFFN.length;
        if (! OK) throw new Exception ("Les 3 tableaux fournis n'ont pas la même taille("+
                                LIMITES.length+","+COEFFR.length+","+COEFFN.length+")");
        // sorun yok
        this.limites=LIMITES;
        this.coeffR=COEFFR;
        this.coeffN=COEFFN;
    }//üretici

     // vergi hesaplaması
    public long calculer(boolean marié, int nbEnfants, int salaire){
         // pay sayısının hesaplanması
        double nbParts;
        if (marié) nbParts=(double)nbEnfants/2+2;
        else nbParts=(double)nbEnfants/2+1;
        if (nbEnfants>=3) nbParts+=0.5;
         // vergilendirilebilir gelir ve aile katsayısı hesaplaması
        double revenu=0.72*salaire;
        double QF=revenu/nbParts;
         // vergi hesaplaması
        limites[limites.length-1]=QF+1;
        int i=0;
        while(QF>limites[i]) i++;
        // sonuç döndürme
        return (long)(revenu*coeffR[i]-nbParts*coeffN[i]);
    }//hesapla
}//sınıf

Bu sınıf, yapıcıya parametre olarak geçirilen üç tablodan limites, coeffR ve coeffN tablolarını oluşturur. Bir veritabanından aynı üç tabloyu oluşturabilen yeni bir yapıcı eklenmesine karar verilir:

  public impots(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

    // dsnIMPOTS: veritabanının adı DSN
     // userIMPOTS, mdpIMPOTS : veritabanına erişim kullanıcı adı/şifre

Örnek olarak, bu yeni oluşturucuyu impots sınıfında değil, türetilmiş bir sınıf olan impotsJDBC sınıfında uygulamaya karar verdik:

// ithal edilen paketler
import java.sql.*;
import java.util.*;

public class impotsJDBC extends impots{
  // oluşturmaya olanak tanıyan bir oluşturucunun eklenmesi
   // tablodan limit, coeffr ve coeffn tablolarını oluşturmaya yarayan bir oluşturucunun eklenmesi
   // bir veritabanından vergi verileri
  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

    // dsnIMPOTS : veritabanının adı DSN
     // userIMPOTS, mdpIMPOTS : veritabanına erişim kullanıcı adı/şifresi

     // veri tabloları
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();

    // veritabanına bağlantı
    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    Connection connect=DriverManager.getConnection("jdbc:odbc:"+dsnIMPOTS,userIMPOTS,mdpIMPOTS);
    // Statement nesnesinin oluşturulması
    Statement S=connect.createStatement();
    // SELECT sorgusu
    String select="select limites, coeffr, coeffn from impots";
    // sorgunun yürütülmesi
    ResultSet RS=S.executeQuery(select);
    while(RS.next()){
      // geçerli satırın işlenmesi
      aLimites.add(RS.getString("limites"));
      aCoeffR.add(RS.getString("coeffr"));
      aCoeffN.add(RS.getString("coeffn"));
    }// sonraki satır
     // kaynakların kapatılması
    RS.close();
    S.close();
    connect.close();
     // verilerin sınırlı tablolara aktarılması
    int n=aLimites.size();
    limites=new double[n];
    coeffR=new double[n];
    coeffN=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffR[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffN[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//for
  }//oluşturucu
}//sınıf

Yapıcı, parametre olarak kendisine aktarılan veritabanındaki impots tablosunun içeriğini okur ve limites, coeffR, coeffN adlı üç tabloyu doldurur. Bir dizi hata meydana gelebilir. Oluşturucu bu hataları yönetmez, ancak bunları çağıran programa "iletir":

  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

Yukarıdaki koda dikkat edilirse, impotsJDBC sınıfının, temel sınıfı olan impotsJDBC'in limites, coeffR ve coeffN alanlarını doğrudan kullandığını görebiliriz. Bu alanlar özel olarak tanımlanmıştır:

    private double[] limites, coeffR, coeffN;

impotsJDBC sınıfı bu alanlara doğrudan erişemez. Bu nedenle temel sınıfa şu şekilde bir değişiklik yapıyoruz:

  protected double[] limites=null;
  protected double[] coeffR=null;
  protected double[] coeffN=null;

protected özniteliği, impots sınıfından türetilen sınıfların bu öznitelikle bildirilen alanlara doğrudan erişebilmesini sağlar. İkinci bir değişiklik yapmamız gerekiyor. impotsJDBC alt sınıfının oluşturucusu şu şekilde bildirilmiştir:

  public impotsJDBC(String dsnIMPOTS, String userIMPOTS, String mdpIMPOTS)
      throws SQLException,ClassNotFoundException{

Bir alt sınıf nesnesini oluşturmadan önce, önce üst sınıf nesnesini oluşturmamız gerektiğini biliyoruz. Bunu yapmak için, alt sınıfın oluşturucusu, super(....) komutuyla üst sınıfın oluşturucusunu açıkça çağırmalıdır. Burada bu yapılmamıştır çünkü üst sınıfın hangi oluşturucusunun çağrılabileceği belli değildir. Şu anda sadece bir tane var ve bu uygun değil. Derleyici, bu durumda ana sınıfta çağırabileceği parametresiz bir oluşturucu arar. Bulamadığı için derleme sırasında bir hata oluşur. Bu nedenle, impots sınıfımıza parametresiz bir oluşturucu ekliyoruz:

   // boş oluşturucu
  protected impots(){}

Bunu, yalnızca alt sınıflar tarafından kullanılabilmesi için "protected" olarak tanımlıyoruz. impots sınıfının iskeleti artık şu şekilde oldu:

public class impots{

  // vergi hesaplaması için gerekli veriler
   // harici bir kaynaktan alınmıştır

  protected double[] limites=null;
  protected double[] coeffR=null;
  protected double[] coeffN=null;

   // boş üretici
  protected impots(){}

   // üretici
  public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception{
...........
  }//üretici

   // vergi hesaplaması
  public long calculer(boolean marié, int nbEnfants, int salaire){
.............
    }//hesapla
}//sınıfı

Uygulamamızdaki Initialiser menüsünün işlevi şu şekilde olur:

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // bağlantı dizesi alınır
    Pattern séparateur=Pattern.compile("\\s*;\\s*");
    String[] champs=séparateur.split(txtConnexion.getText().trim());
     // üç alan gereklidir
    if(champs.length!=3){
      // hata
      txtStatus.setText("Chaîne de connexion (DSN;uid;mdp) incorrecte");
       // görsel arayüze geri dön
      txtConnexion.requestFocus();
      return;
    }//if
     // veriler yükleniyor
    try{
       // impotsJDBC nesnesinin oluşturulması
      objImpots=new impotsJDBC(champs[0],champs[1],champs[2]);
       // onay
      txtStatus.setText("Données chargées");
       // maaş değiştirilebilir
      txtSalaire.setEditable(true);
       // artık değişiklik yapılamaz
      mnuInitialiser.setEnabled(false);
      txtConnexion.setEditable(false);
    }catch(Exception ex){
       // sorun
      txtStatus.setText("Erreur : " + ex.getMessage());
      // son
      return;
    }//yakalama
  }

objImpots nesnesi oluşturulduktan sonra, uygulama daha önce yazılmış olan grafik uygulamayla aynıdır. Okuyucunun bu uygulamaya başvurması önerilir.

6.4. Alıştırmalar

6.4.1. Alıştırma 1

Yukarıdaki sql3 programına bir grafik arayüz ekleyin.

6.4.2. Alıştırma 2

Bir Java applet'i, yalnızca yüklendiği sunucu aracılığıyla bir veritabanına erişebilir. Zira, bir applet, üzerinde çalıştırıldığı makinenin diskine erişemediğinden, veritabanı applet'i kullanan istemcinin makinesinde bulunamaz. Dolayısıyla şu durum söz konusudur:

Image

Applet'i çalıştıran makine, sunucu ve veritabanının bulunduğu makine birbirinden farklı üç makine olabilir. Burada veritabanının sunucuda bulunduğu varsayılmaktadır.

Sorun 1

Aşağıdaki sunucu uygulamasını Java ile yazınız:

  • sunucu uygulaması, kendisine parametre olarak verilen bir bağlantı noktasında çalışır
  • bir istemci bağlandığında, sunucu uygulaması şu mesajı gönderir
200 - Bienvenue - Envoyez votre requête
  • ardından istemci, veritabanına bağlanmak için gerekli parametreleri ve yürütmek istediği sorguyu şu biçimde gönderir:
Pilote Java/URL base/UID/MDP/requête SQL

Parametreler eğik çizgiyle ayrılır. İlk dört parametre, bu bölümde açıklanan sql3 programına aittir.

  • Ardından sunucu uygulaması, kendisiyle aynı makinede bulunması gereken belirtilen veritabanıyla bir bağlantı kurar ve bu veritabanı üzerinde SQL sorgusunu yürütür. Sonuçlar, aşağıdaki biçimde istemciye gönderilir:
100 - ligne1
100 - ligne2

...

eğer bir Select sorgusunun sonucuysa veya

101 - nbLignes

bir güncelleme sorgusundan etkilenen satır sayısını döndürmek için. Veritabanına bağlanma veya sorgunun yürütülmesi sırasında bir hata oluşursa, uygulama

500 - Message d’erreur
  • değerini döndürür; sorgu yürütüldükten sonra sunucu uygulaması bağlantıyı kapatır.

Sorun 2

Önceki sunucuyu sorgulayabilen bir Java uygulaması oluşturun. Önceki Alıştırma 1’deki grafik arayüzünden ilham alabilirsiniz. Sunucunun bağlantı noktası değişkenlik gösterebileceğinden, bu değer uygulama arayüzünde girilecektir. Satırı göndermek için gerekli tüm parametreler için de aynı durum geçerlidir:

Pilote Java/URL base/UID/MDP/requête SQL

satırını sunucuya göndermesi gereken tüm parametreler için de aynı durum geçerlidir.

6.4.3. Alıştırma 3

Aşağıdaki metin, başlangıçta Visual Basic ile çözülmesi amaçlanan bir problemi açıklamaktadır. Bunu, bir applet içinde Java ile işlenecek şekilde uyarlayın. Bu applet, Alıştırma 2’deki sunucuyu kullanacaktır. Grafik arayüz, yeni çalışma ortamını dikkate alacak şekilde değiştirilebilir.

ACCESS adlı bir veritabanındaki tablonun güncellenmesine ilişkin çeşitli işlemleri gösteren bir uygulama oluşturulması amaçlanmaktadır. ACCESS veritabanının adı articles.mdb'tir. Bu veritabanında, bir şirket tarafından satılan ürünleri listeleyen "articles" adlı tek bir tablo bulunmaktadır. Tablonun yapısı şöyledir:

ad
tür
code
4 karakterlik ürün kodu
nom
adı (karakter dizisi)
prix
fiyatı (gerçek)
stock_actu
mevcut stoğu (tamsayı)
stock_mini
ürünün yeniden stoklanması gereken minimum stok miktarı (tamsayı)

Aşağıdaki form aracılığıyla bu tabloyu görüntülemek ve güncellemek istiyoruz:

Image

Bu formdaki kontrol alanları şunlardır:

No
tür
ad
İşlev
1
metin kutusu
kayıt
Görüntülenen kaydın numarası
enabled değeri false
2
metin kutusu
kod
ürün kodu
3
metin kutusu
ad
ürün adı
4
metin kutusu
fiyat
ürünün fiyatı
5
textbox
mevcut
ürünün mevcut stoğu
6
textbox
minimum
ürünün minimum stoğu
7
data
data1
Veritabanıyla ilişkili veri denetimi
databasename=articles.mdb dosyasının yolu
kayıt kaynağı=makaleler
connect=access
8
HScrollBar
konum
tabloda gezinmeyi sağlar
9
düğme
OK
bir güncellemeyi onaylamaya yarar - yalnızca güncelleme sırasında görünür
10
düğme
İptal
bir güncellemeyi iptal etmenizi sağlar - yalnızca güncelleme sırasında görünür
11
frame
frame1
görsel açıdan daha hoş olması için
12
textbox
dosya adı
açık veritabanının adı
enabled değeri false
13
textbox
sourcename
açık tablonun adı
enabled değeri false

VB altında sayfanın oluşturulması

denetim
Özellikler
data1
databasename ve recordsource alanları doldurulmuştur. databasename, dizininizdeki articles.mdb adlı Access veritabanını, recordsource ise articles tablosunu belirtmelidir.
code
Bu, data1'deki geçerli kaydın code alanına bağlamak istediğimiz bir metin kutusudur. Bunun için iki alanı doldururuz:
datasource: metin kutusunun data1 ile ilişkili tabloya bağlı olduğunu belirtmek için data1 yazılır
datafield: articles tablosundaki code alanını seçin
Bu işlemlerin ardından, "code" metin kutusu her zaman data1'deki geçerli kaydın "code" alanını içerecektir. Tersine, bu metin kutusunun içeriğini değiştirmek, geçerli kaydın "code" alanını da değiştirecektir.
Diğer metin kutuları için de aynı işlemi gerçekleştirin
nom
veri kaynağı: data1 veri alanı: nom
prix
veri kaynağı: data1 veri alanı: fiyat
actuel
veri kaynağı: data1 veri alanı: stock_actu
minimum
veri kaynağı: data1 veri alanı: stock_mini

Menüler

Menülerin yapısı şu şekildedir

Düzenle
Gözat
Çık
Ekle
Geri
 
Düzenle
Sonraki
 
Sil
İlk
 
 
Son
 

Farklı seçeneklerin işlevleri şunlardır:

menü
name
işlev
Ajouter
mnuekle
ürün tablosuna yeni bir kayıt eklemek için
Supprimer
mnusupprimer
ürünler tablosundan şu anda görüntülenen kaydı silmek için
Modifier
mnumodify
ürün tablosunda şu anda görüntülenen kaydı düzenlemek için
Précédent
mnuprecedent
önceki kayda geçmek için
Suivant
mnusuivant
bir sonraki kayda geçmek için
Premier
önceki
bir önceki kayda geçmek için
Dernier
mnudernier
son kayda geçmek için
Quitter
mnuçık
uygulamadan çıkmak için

Sayfa yükleniyor

form_load olayı sırasında, data1 ile ilişkili tablo açılır (data1.refresh). Açma işlemi başarısız olursa, bir hata mesajı görüntülenir ve program sonlandırılır (end). Aksi takdirde, articles tablosunun ilk kaydı görüntülenerek form ekrana getirilir. Alanlara giriş yapılamaz (enabled özelliği false olarak ayarlanmıştır). Giriş, yalnızca Ekle ve Düzenle seçenekleriyle mümkündür. OK ve İptal düğmeleri gizlenmiştir (visible=false).


Bölüm 1

Menüdeki çeşitli seçeneklerle ve OK ile İptal düğmeleriyle ilgili prosedürleri oluşturmayı amaçlıyoruz. İlk etapta, aşağıdaki noktaları göz ardı edeceğiz:

  • menüdeki belirli seçeneklerin etkinleştirilmesi/devre dışı bırakılması: örneğin, tablonun son kaydında bulunuluyorsa “İleri” seçeneği devre dışı bırakılmalıdır
  • yatay kaydırma çubuğunun yönetimi

Gözat/İleri menüsü

  • dosyanın sonuna gelinmemişse (data1.RecordSet.EOF) bir sonraki kayda (data1.RecordSet.MoveNext) geçer. Kayıt metin kutusunu günceller (data1.recordset.absoluteposition/ data1.recordset.recordcount).

Gözat menüsü/Önceki

  • Dosyanın başında değilse (data1.RecordSet.BOF), bir önceki kayda (data1.RecordSet.MovePrevious) geçer. Kayıt metin kutusunu günceller.

Gözat/İlk menüsü

  • dosya boş değilse (data1.recordset.recordcount=0), ilk kayda (data1.RecordSet.MoveFirst) geçer. Kayıt metin kutusunu günceller.

Gözat menüsü/Son

  • dosya boş değilse (data1.recordset.recordcount=0) son kayda geçer (data1.RecordSet.MoveLast). Kayıt metin kutusunu günceller.

Düzenle/Ekle menüsü

  • tabloya bir kayıt eklemenizi sağlar
  • Kayıt Ekleme moduna geçer (data1.recordset.addnew)
  • kod, ad, fiyat gibi 5 alana giriş yapılmasına izin verir (enabled=true)
  • Düzenle, Gözat ve Çık menülerini devre dışı bırakır (enabled=false)
  • OK ve İptal düğmelerini görüntüler (visible=true)

OK düğmesi

  • kayıt değişikliğini onaylar (data1.recordset.Update)
  • OK ve İptal düğmelerini gizler (visible=false)
  • Düzenle, Gözat ve Çık seçeneklerini etkinleştirir (enabled=true)
  • kayıt metin kutusunu günceller

İptal düğmesi

  • kayıt değişikliğini geçersiz kılar (data1.recordset.CancelUpdate)
  • OK ve İptal düğmelerini gizler (visible=false)
  • Düzenle, Gözat, Çık seçeneklerini etkinleştirir (enabled=true)
  • kayıt metin kutusunu günceller

Düzenle/Değiştir menüsü

  • formda görüntülenen kaydı düzenlemeye izin verir
  • kayıt Düzenleme moduna geçirir (data1.recordset.edit)
  • ad, fiyat vb. 4 alana giriş yapılmasına izin verir (enabled=true), ancak kod alanına giriş yapılmasına izin vermez (enabled=false)
  • Düzenle, Gözat ve Çık menülerini devre dışı bırakır (enabled=false)
  • OK ve İptal düğmelerini görüntüler (visible=true)

Düzenle/Sil menüsü

  • tablodaki görüntülenen kaydı silmeye (data1.recordset.delete) olanak tanır
  • bir sonraki kayda geçer (data1.recordset.movenext)

Çıkış menüsü

  • sayfayı boşaltır (unload me)

form_unload olayı (cancel as integer)

  • "unload me" işlemi veya Alt-F4 tuşlarıyla formun kapatılması ya da sistem kutucuğuna çift tıklama ile etkinleştirilir; dolayısıyla mutlaka "çıkış" seçeneği ile gerçekleşmez.
  • "Uygulamadan gerçekten çıkmak istiyor musunuz?" sorusunu iki düğmeyle (Evet/Hayır) görüntüler (style=vbyes+vbno ile msgbox)
  • Cevap Hayır ise (=vbno), cancel değerini -1 olarak ayarlar ve form_unload yordamından çıkar. cancel değerinin -1 olması, pencerenin kapatılmasının reddedildiğini gösterir.
  • Cevap Evet ise (=vbyes), veritabanı kapatılır (data1.recordset.close, data1.database.close).

Bölüm 2 - Menü Yönetimi

Burada menülerin etkinleştirilmesi/devre dışı bırakılması ele alınmaktadır. Geçerli kaydı değiştiren her işlemden sonra, Oueston olarak adlandırabileceğimiz bir prosedür çağrılacaktır. Bu prosedür aşağıdaki koşulları kontrol edecektir:

. Dosya boşsa,

  • Gözat, Düzenle/Sil menüleri devre dışı bırakılacak,
  • diğer menüler ise etkinleştirilecektir

. Geçerli kayıt ilk kayıt ise,

  • Gözat/Önceki
  • geri kalanlara izin verilir

. Mevcut kayıt son kayıt ise,

  • "Gözat/Sonraki" seçeneği devre dışı bırakılır
  • diğerleri etkinleştirilir

Bölüm 3 - Yatay kaydırma çubuğunun yönetimi

Bir yatay kaydırıcının üç önemli alanı vardır:

  • min: minimum değeri
  • max: maksimum değeri
  • value: mevcut değeri

Sürücünün başlatılması

Yükleme sırasında (form_load), sürücü şu şekilde başlatılacaktır:

  • min=0
  • max=data1.recordset.recordcount-1
  • value=1

Veritabanının açılmasından hemen sonra (data1.refresh), data1.recordset.recordcount ile temsil edilen tablonun kayıt sayısı yanlış olacaktır. Bunun doğru olması için tablonun sonuna (MoveLast) gidip ardından tablonun başına (MoveFirst) geri dönmek gerekir.

Sürücü üzerinde doğrudan işlem

Sürücünün imleci, tablodaki konumu temsil eder.

Kullanıcı sürücüyü (burada "konum" olarak adlandırılır) değiştirdiğinde, position_change olayı tetiklenir. Bu olayda, kontrol cihazında yapılan hareketi yansıtacak şekilde tablodaki geçerli kaydı değiştireceğiz. Bunun için data1.recordset olayındaki absoluteposition alanını kullanacağız. Bu alana i değeri atandığında, tablodaki i numaralı kayıt geçerli kayıt haline gelir. Kayıtlar 0'dan başlayarak numaralandırılır ve dolayısıyla [0,data1.recordset.recordcount-1] aralığında bir numaraya sahiptir. position_change prosedüründe şunları yazmamız yeterlidir:

    data1.recordset.absoluteposition=position.value

yazmamız yeterlidir; böylece formda görüntülenen geçerli kayıt, sürücü üzerinde yapılan ayarlamayı yansıtacaktır.

Bu işlem tamamlandıktan sonra, menüleri güncellemek için Oueston prosedürünü çağıracağız.

Variatörün güncellenmesi

Variatörün imlecinin konumu, tablodaki konumu yansıtması gerektiğinden, menülerden herhangi biri tarafından tabloda geçerli kayıtta bir değişiklik olduğu her seferinde variatörün değeri güncellenmelidir. Bu menülerin her biri Oueston prosedürünü çağırdığından, bu güncellemeyi de bu prosedüre yerleştirmek en uygunudur. Buraya şunu yazmak yeterlidir:

    position.value=data1.recordset.absoluteposition

Bölüm 4 - Ara Seçeneği

Kullanıcının kodunu verdiği bir ürünü görüntüleyebilmesini sağlamak amacıyla Gözat/Ara seçeneği eklenir.

Bu seçenek etkinleştirildiğinde, aşağıdaki adımlar gerçekleşir:

  • Kayıt Ekle (Addnew) moduna geçilir; bunun tek amacı, seçeneğin etkinleştirildiği sırada üzerinde çalışılan mevcut kaydı değiştirmemek içindir,
  • Kod alanına giriş yapılmasına izin verilir ve kayıt alanının içeriği silinir,
  • menüler devre dışı bırakılır ve OK ile İptal düğmeleri görüntülenir
  • kullanıcı OK düğmesine bastığında, kullanıcının girdiği koda karşılık gelen kaydı aramamız gerekir. Ancak OK_click prosedürü zaten Gözat/Ekle ve Gözat/Değiştir seçenekleri için kullanılmaktadır. Bu durumları birbirinden ayırt etmek için, burada “durum” olarak adlandıracağımız ve üç olası değeri olan (“ekle”, “değiştir” ve “ara”) bir küresel değişkeni yönetmemiz gerekiyor. OK ve İptal düğmelerine bağlı prosedürler, hangi bağlamda çağrıldıklarını belirlemek için bu değişkeni kullanacaklardır.
  • Eğer durum “ara” değerindeyse, OK ile ilişkili prosedürde
    • addnew işlemi (data1.recordset.cancelupdate) iptal edilir, çünkü bir kayıt ekleme niyetinde değildik. Bu durumda, geçerli kaydın, Gözat/Ara işleminden önce ekranda bulunan kayıt haline geri döndüğü unutulmamalıdır.
    • koda ilişkin arama kriteri oluşturulur ve arama başlatılır (data1.recordset.findfirst kriter),
    • arama başarısız olursa (data1.recordset.nomatch=true), kullanıcıya bildirimde bulunulur, ardından tekrar ekleme moduna (addnew) geçilir ve OK prosedüründen çıkılır. Kullanıcı yeni bir kod girmeli veya İptal seçeneğini seçmelidir.
    • Arama başarılı olursa, bulunan kayıt yeni geçerli kayıt olur. Menüler yeniden görüntülenir, OK/İptal düğmeleri gizlenir, kod alanına giriş engellenir ve prosedürden çıkılır.
  • . Durum "ara" ise, İptal ile ilişkili prosedürde
    • addnew işlemi (data1.recordset.cancelupdate) iptal edilir. Ardından, "Gözat/Ara" işleminden önceki geçerli kayda otomatik olarak geri dönülür.
    • menüleri geri yükler, OK/İptal düğmelerini gizler, kod alanına giriş yapılmasını engeller ve prosedürden çıkılır.

Bölüm 5 - Kod Yönetimi

Bir ürün, kodu ile benzersiz bir şekilde tanımlanmalıdır. Gözat/Ekle seçeneğinde, eklenecek kaydın ürün kodu tabloda zaten mevcutsa ekleme işleminin reddedilmesini sağlayın.

6.4.4. Alıştırma 4

Burada, Alıştırma 2'deki sunucuyu temel alan bir web uygulaması sunulmaktadır. Bu, bir e-ticaret uygulamasının ilk aşamasıdır.

Müşteri, aşağıdaki web arayüzü aracılığıyla ürün siparişi verir:

Image

Müşteri şu işlemleri yapabilir:

  • açılır listeden bir ürün seçebilir
  • İstediği miktarı belirtir
  • Acheter düğmesiyle satın alma işlemini onaylar
  • satın alımı, satın alınan ürünler listesinde görüntülenir
  • bir ürünü seçip Retirer düğmesini kullanarak bu listeden ürünleri kaldırabilir
  • Bilan düğmesine bastığında, aşağıdaki özeti görür:

Image

Özet, kullanıcının faturasının ayrıntılarını görmesini sağlar. Kullanıcı, Informations düğmesi ile açılır listeden seçtiği bir kaleme ilişkin ayrıntılara erişebilir:

Image

Kullanıcı fatura dökümünü talep ettikten sonra, bir sonraki sayfadan faturayı onaylayabilir. Bunun için e-posta adresini girmeli ve ilgili düğmeyi kullanarak siparişini onaylamalıdır.

Image

Siparişini kaydetmeden önce uygulama onay ister:

Image

Sipariş onaylandıktan sonra, uygulama siparişi işler ve bir onay sayfası gönderir:

Image

Aslında uygulama siparişi işleme almaz. Sadece kullanıcıya, alışveriş tutarını ödemesini isteyen bir e-posta gönderir:

Cher client,

Vous trouverez ci-dessous le détail de votre commande au magasin SuperPrix. Elle vous sera livrée après réception de votre chèque établi à l'ordre de SuperPrix et à envoyer à l'adresse suivante :

SuperPrix 
ISTIA 
62 av Notre-Dame du Lac 
49000 Angers 
France

Nous vous remercions vivement de votre commande

---------------------------------------- 
Votre commande 
---------------------------------------- 
article, quantité, prix unitaire, total 
======================================== 
vélo, 2, 1202.00 F, 2404.00 F 
skis nautiques, 3, 1800.00 F, 5400.00 F
Total à payer : 7804 F

Soru: Bu web uygulamasının eşdeğerini bir Java applet ile oluşturun.