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:

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

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:

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:
- Veritabanına bağlanma
- Veritabanına SQL sorgularının gönderilmesi
- Bu sorguların sonuçlarının alınması ve işlenmesi
- Bağlantının kapatılması
- 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:


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

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:
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 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:
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 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:
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.
- "from" anahtar sözcüğünün ardından gelen tüm tablolarla bir birleştirme işlemi yapılır
- Yalnızca "select" anahtar sözcüğünün ardından gelen sütunlar tutulur
- Yalnızca "where" anahtar sözcüğündeki koşulu karşılayan satırlar tutulur
- "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:
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:
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:
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:
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:
ResultSetMetaData sınıfında iki yararlı yöntem dikkat çekmektedir:
- getColumnCount() yöntemi, ResultSet'in sütun sayısını verir
- 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:
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:
İ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:
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 été 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 été 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 été 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:

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 adındaki veri kaynağının adı ODBC | |
| veritabanında okuma hakkına sahip bir kullanıcının kimliği |
| ş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

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

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

- 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:
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 ö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:
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:

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
- ardından istemci, veritabanına bağlanmak için gerekli parametreleri ve yürütmek istediği sorguyu şu biçimde gönderir:
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:
...
eğer bir Select sorgusunun sonucuysa veya
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
- 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:
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:

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 |
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ü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 |
mnuekle | ürün tablosuna yeni bir kayıt eklemek için | |
mnusupprimer | ürünler tablosundan şu anda görüntülenen kaydı silmek için | |
mnumodify | ürün tablosunda şu anda görüntülenen kaydı düzenlemek için | |
mnuprecedent | önceki kayda geçmek için | |
mnusuivant | bir sonraki kayda geçmek için | |
önceki | bir önceki kayda geçmek için | |
mnudernier | son kayda geçmek için | |
mnuçık | uygulamadan çıkmak için |
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).
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).
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
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:
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:
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.
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:

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:

Ö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:

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.

Siparişini kaydetmeden önce uygulama onay ister:

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

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.

