Skript zur Einführung

Werbung
Datenbank-Programmierung mit JDBC
Weiterbildungsmaßnahme Technische und Praktische Informatik
Sommersemester 2003
DBIS
@
BTU
Cottbus
Dipl.-Inf. Gunar Fiedler
1
Motivation für JDBC
Auf dem Markt existiert eine Vielzahl verschiedener relationaler DBM-Systeme. Sie
alle (bzw. die meisten) haben eines gemeinsam: sie sprechen“ SQL, d.h. sie sind in
”
der Lage, in SQL formulierte Anfragen und Update-Anweisungen zu verarbeiten.
Möchte man als Applikationsentwickler diese Funktionalität nutzen, muss das Programm SQL-Anweisungen generieren und an das Datenbank-Management-System
schicken. Der Programmierer steht dabei aber vor dem Problem, dass für die einzelnen Systeme über die Zeit hinweg unabhängig voneinander unterschiedliche Zugriffsmechanismen entwickelt wurden. Dies bedingt, dass man sich schon zu Beginn
eines Softwareprojekts auf ein bestimmtes DBMS, ja sogar auf eine bestimmte Version festlegen müsste. Ein Wechsel des verwendeten DBMS bedeutet in diesem Fall
umfangreiche Änderungen im Code der Applikation.
Dem Credo der Datenbanken folgend sollte es aber möglich sein, die Verarbeitungslogik der Anwendung so weit wie möglich von der Datenbank abzukoppeln. Um dies
zu erreichen, bedient man sich einer Treiber-Architektur. Die Anwendung wird von
der Datenbank durch eine weitere Softwarekomponente, Treiber genannt, getrennt.
Ein Treiber stellt der Anwendung eine für alle DBMS einheitlich definierte Schnittstelle zur Verfügung und implementiert intern die Protokolle für ein ganz bestimmtes
System.
Soll nun das DBMS ausgetauscht werden, so muss lediglich ein anderer Treiber in
die Anwendung eingebunden werden. Umgedreht ist der Treiber unabhängig von der
Applikationslogik und kann auch in anderen Anwendungen wiederverwendet werden.
Mit der Java Database Connectivity, kurz JDBC, steht Java-Programmierern eine
standardisierte Umgebung für den Zugriff auf beliebige relationale Datenbanken zur
Verfügung. Zu diesem Zweck definiert JDBC eine Reihe von Schnittstellen und Mechanismen, die automatisch in allen Java-Entwicklungs- und Laufzeitumgebungen
zur Verfügung stehen.
2 Grundgerüst eines JDBC-basierten Programms
JDBC-Grundlagen
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
..
......
......
......
......
JDBCTreiber
..
......
......
......
......
..
......
......
......
......
JDBCTreiber
..
......
......
......
......
..
......
......
......
......
..
......
......
......
......
JDBCTreiber
..
......
......
......
......
..
......
......
......
......
..
......
......
......
......
..
......
......
......
......
ODBCTreiber
.
......
......
......
......
..........................................................................................................................................
..............................
....................
.........
.........
......
......
....
...
....
.....
.
....
..
......
.....
.........
.......
.
.
.
.
.
.
..................
.
.
.
..............................
Sybase
......
.
.....
......
......
.......
.......
...........
..................................
..............................
....................
.........
.........
......
......
....
...
....
.....
.
....
..
......
.....
.........
.......
.
.
.
.
.
.
..................
.
.
.
..............................
Oracle
......
......
......
......
.......
.......
...........
..................................
..............................
....................
.........
.........
......
......
....
...
....
.....
..
....
..
......
.....
.........
.......
.
.
.
.
.
.
..................
.
.
.
..............................
CSV-Datei
......
......
......
......
.......
.......
...........
..................................
Abbildung 1: Aufbau einer JDBC-basierten Applikation
2
Grundgerüst eines JDBC-basierten Programms
Abbildung 1 zeigt den Grobaufbau einer JDBC-basierten Applikation. Sie besteht
aus 3 Schichten:
• Applikationslogik: Sie definiert die Verarbeitungsregeln der Geschäftsprozesse.
• JDBC-Datenbanktreiber: Er kapselt die Spezifika des Datenbanksystems
und stellt der Applikationslogik die Daten der Datenbank mit Hilfe einer standardisierten Schnittstelle zur Verfügung.
• Datenbank: Speichert die Daten. Der Treiber kommuniziert mit der Datenbank über ein DBMS-spezifisches Protokoll.
Aus Sicht des Java-Programmierers ist ein JDBC-Datenbanktreiber ein Package bestehend aus einer Reihe von Klassen. Die Klassen implementieren die Interfaces des
Standard-Packages java.sql. Diese Interfaces erlauben das datenbankunabhängige Programmieren mit Hilfe von JDBC: die Anwendung sieht“ nur ein java.sql”
Interface, welche Klasse aus welchem Treiber letztlich instanziiert wurde, bleibt verborgen.
2
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
2 Grundgerüst eines JDBC-basierten Programms
Der Zugriff auf eine Datenbank über JDBC innerhalb eines Java-Programms lässt
sich in einzelne Phasen aufteilen, die nacheinander ausgeführt werden müssen, Abbildung 2 zeigt eine Übersicht.
pppppp
Laden des Treibers
ppppppppp
ppppp
Herstellen der Verbindung
zum DBMS
pppppppp
ppppp
Erzeugen eines
Statement-Objekts
ppppppppp
ppp
pppw
ppppppppppppp ppppppppppppppppppppppppppppp
p
p
p
p
p
p
p
p
p
p
p
ppppppppppppppp
ppp
ppppppppppppppp
ppppppppppppp
p
p
p
p
p
p
p
p
p
p
ppppppppppppppp
p
p
pppp
ppppppppppppppp
pp pppppppppp
p
p
p
p
p
p
p
ppppppppppppppp
p
p
p
p
p
p
pppppppppp
ppppppppppppppppp
Ausführen
einer Anfrage
w
Ausführen
eines Updates
ppp pp
Auswertung
der Ergebnisse
p
pppppppppp
pppp pppppppp
pppppppppp
ppp ppppppppp
pppppppppp
pp pppppppppp
p
p
p
p
p
p
pppppppppp
p
p
p
p
p
ppppp
pppppppppp
pppp pppppppp
pppppppppp
ppp ppppppppp
pppppppppp
pp pppppppppp
p
pppppppppp
p
p
p
p
p
p
p
p
p
p
pppppppppp
ppppppppppp
ppppppppppw
pppppppppp pp
w
ppppp
Schließen
der Verbindung
Abbildung 2: Phasen des Datenbankzugriffs
1. Laden des Treibers:
In dieser Phase werden die Klassen des JDBC - Treibers dynamisch in die
Anwendung eingebunden und registriert.
2. Herstellen der Verbindung:
Der Treiber baut eine Verbindung zum DBMS auf.
3. Erzeugen eines Statements:
Statements sind die JDBC-Repräsentation für SQL-Anweisungen. Bevor ei-
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
3
3 Die Phasen im Detail
JDBC-Grundlagen
ne SQL-Anfrage gestartet werden kann, muss sie in ein Statement verpackt“
”
werden.
4. Ausführen des Statements:
Die SQL-Anfrage wird an das DBMS übermittelt und dort ausgeführt. Die
Resultate werden zurückgeliefert.
5. Auswertung der Ergebnisse:
Über die Methoden des Interfaces java.sql.ResultSet kann das Ergebnis
einer Anfrage ausgewertet werden.
6. Schließen der Verbindung:
um nicht weiter benötigte Ressourcen freizugeben.
3
Die Phasen im Detail
Dieser Abschnitt verdeutlicht die einzelnen Phasen eines JDBC-Zugriffs anhand
von Codebeispielen und Abbildungen. Grundlage bildet wieder unsere 3-SchichtenAnwendung:
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
..
......
......
......
......
Sybase-Treiber
..
......
......
......
......
..........................................................................................................................................
.................................
..................
.........
.........
......
......
....
....
...
.....
..
....
....
......
.........
......
..................
.........
.................................
Sybase
......
......
......
......
.......
.......
...........
...................................
3.1
Laden des Treibers
Wie bereits angedeutet, ist ein JDBC-Datenbanktreiber nichts anderes als ein Package diverser Java-Klassen, welche die Interfaces aus java.sql implementieren. Jeder
Treiber enthält als Repräsentanten eine Hauptklasse“. Über diese Klasse wird der
”
Treiber identifiziert und angesprochen.
Eine zentrale JDBC-Komponente ist der Treibermanager. Er wird durch die Klasse
java.sql.DriverManager repräsentiert und ist zuständig für die Verwaltung und
den Zugriff auf die Datenbanktreiber. Ein Treiber steht der Anwendung erst zur
Verfügung, wenn er sich beim Treibermanager registriert hat.
4
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
3 Die Phasen im Detail
Das dynamische Laden eines Treibers gestaltet sich genauso wie das Laden jeder anderen beliebigen Java-Klasse. Angenommen, wir möchten den Treiber für
Sybase-Datenbanken laden. Die Hauptklasse“ des JDBC-Treibers hat den Namen
”
com.sybase.jdbc2.jdbc.SybDriver:
try
{
C l a s s . forName ( ”com . s y b a s e . j d b c 2 . j d b c . S y b D r i v e r ” ) ;
}
catch ( C l a s s N o t F o u n d E x c e p t i o n e )
{
// F e h l e r b e h a n d l u n g , f a l l s K l a s s e n i c h t g e f u n d e n wurde
}
Die Treiberklasse sorgt automatisch für eine Registrierung beim Treibermanager.
Das Laden des Treibers muss nur einmal während der Initialisierungsphase durchgeführt werden, der Treiber steht bis zum Ende der Applikation zur Verfügung:
.
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
..
......
......
......
......
Sybase-Treiber
..
......
......
......
......
..........................................................................................................................................
...............................
...................
.........
.........
......
......
....
....
...
.....
...
....
....
......
......
.........
.
.
.
.
.
.
..................
....
.................................
Sybase
......
.
......
.....
.......
......
...........
.......
..................................
3.2
Herstellen der Verbindung
Nachdem der Datenbank-Treiber in die Anwendung integriert wurde, kann die Verbindung zur Datenbank geöffnet werden. Dafür sind die folgenden Informationen
von Bedeutung:
• Welcher Treiber soll benutzt werden?
• Wie heißt die Datenbank und wo befindet sie sich?
• Mit welchen Daten authentifiziere ich mich gegenüber der Datenbank?
• ...
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
5
3 Die Phasen im Detail
JDBC-Grundlagen
Das Öffnen der Verbindung wird durch den Treibermanager und dessen statische Methode getConnection() veranlasst. Diese Methode liefert ein Objekt zurück, dessen
Klasse das Interface java.sql.Connection implementiert. Die oben genannten Daten werden der Methode in Form einer URL (uniform resource locator) übergeben.
Diese URL hat die folgende standardisierte Form:
jdbc:<subprotocol>:<subURL>
Über die Zeichenkette <subprotocol> wird der gewünschte Treiber spezifiziert. Der
Inhalt von <subURL> hängt vom konkreten Treiber ab. Der Sybase-Treiber erwartet
beispielsweise folgende URL:
jdbc:sybase:Tds:<host>:<port>/<database>?<parameter>
Die Kombination aus <host> und <port> gibt dabei den Server an, auf dem sich die
Datenbank befindet, <database> spezifiziert den Namen der Datenbank. Zusätzliche
Parameter können in der Form <name>=<wert> nach dem Fragezeichen angegeben
werden. Möglich sind z.B. die Authentifizierungsdaten (user und password), auch
der Name der Datenbank kann alternativ als Parameter servicename übergeben
werden.
Angenommen, der Nutzer joe (Passwort: foo) möchte die Sybase-Datenbank namens Personal auf dem Rechner dbserver nutzen. Das DBMS ist über Port 1234
erreichbar.
Es gibt 3 verschiedene Varianten der DriverManager.getConnection-Methode:
• DriverManager.getConnection(String url):
Der allgemeine Fall. Alle Daten müssen gemäß der oben genannten Vorschrift
in eine URL verpackt werden:
String url =
”j d b c . s y b a s e : Tds : d b s e r v e r : 1 2 3 4 ” +
”/ P e r s o n a l ? u s e r=j o e&p a s s w o r d=f o o ” ;
C o n n e c t i o n conn =
DriverManager . getConnection ( u r l ) ;
• DriverManager.getConnection(String url, Properties info):
Der Methode wird zusätzlich ein assoziatives Array info übergeben, welches
die Parameter aufnehmen kann, die normalerweise nach dem Fragezeichen der
URL stehen würden. Sinnvoll ist diese Trennung, wenn diese Parameter dynamisch generiert werden. Dann entfällt die umständliche Kodierung der URL:
P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ;
p r o p s . pu t ( ”u s e r ” , ”j o e ” ) ;
p r o p s . pu t ( ”p a s s w o r d ” , ”f o o ” ) ;
p r o p s . pu t ( ”s e r v i c e n a m e ” , ”P e r s o n a l ” ) ;
S t r i n g u r l = ”j d b c : s y b a s e : Tds : d b s e r v e r : 1 2 3 4 ” ;
6
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
3 Die Phasen im Detail
C o n n e c t i o n conn =
DriverManager . getConnection ( url , props ) ;
• DriverManager.getConnection(String url, String user, String password):
Analog zur 2. Variante, falls als Parameter nur Nutzername und Passwort
benötigt werden:
String url =
”j d b c . s y b a s e : Tds : d b s e r v e r : 1 2 3 4 / P e r s o n a l ” ;
C o n n e c t i o n conn =
D r i v e r M a n a g e r . g e t C o n n e c t i o n ( u r l , ”j o e ” , ”f o o ” ) ;
Nach Abschluss dieser Phase besteht eine Kommunikationsverbindung zwischen Applikation und der Datenbank:
..
......
......
......
......
.
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
...
.........
.........
.........
...
.........
.........
.........
Sybase-Treiber
...
.........
.........
.........
qqqq
qq
qqqqq
qqqqq
..........................................................................................................................................
..............................
....................
.........
.........
......
......
....
....
...
.....
...
....
....
......
.....
.........
.........
..................
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
...................
qqq
Sybase
......
.
.....
......
.......
......
...........
.......
..................................
3.3
Erzeugen eines Statements
SQL-Anfragen werden unter JDBC in Statement-Objekte eingekapselt. Bevor eine
Anfrage ausgeführt werden kann, muss ein derartiges Objekt erzeugt werden. Dies
geschieht durch Aufruf der createStatement-Methode des im vorherigen Schritt
erzeugten Connection-Objekts:
S t a t e m e n t stmt = conn . c r e a t e S t a t e m e n t ( ) ;
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
7
3 Die Phasen im Detail
JDBC-Grundlagen
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
...
.........
.........
.........
...
.........
.........
.........
Sybase-Treiber
.................................................
..............
........
.......
.....
.....
..
..
....
.......
.............
....................................................
qqqqqqqqqqqqqq................
stmt
...
.........
.........
.........
qqq
qqq
qqqqq
qqqq
..........................................................................................................................................
..
........................ ................................
......
.........
.....
......
....
...
.....
.
....
...
......
....
.........
......
.
.
.
.
.
.
.
.
..................
.................................
qqqq
Sybase
......
......
......
......
.......
.......
...........
...................................
Neben einfachen SQL-Anfragen, wie wir sie hier betrachten, können über StatementObjekte auch spezielle vorcompilierte Anfragen (prepared statements) und stored
procedures ausgeführt werden. Außerdem lässt sich über die Statement-Objekte die
Rückgabe des Ergebnisses steuern. Zu beachten ist: ein einzelnes Statement kann
nicht mehrere SQL-Anfragen gleichzeitig verwalten. Ergebnisse müssen verarbeitet
werden, bevor eine neue Anfrage gestellt wird.
3.4
Ausführen eines Statements
Das Statement-Objekt stellt Methoden zum Ausführen von SQL-Anweisungen bereit. Aufgrund der unterschiedlichen Bedürfnisse werden zwei verschiedene Anweisungsarten unterschieden: Anfragen und Updates.
Anfragen sind SQL-Anweisungen, die ein Ergebnis zurückliefern, typischerweise select - Anweisungen. Sie werden über die executeQuery-Methode des StatementObjekts ausgeführt, diese Methode nimmt die Anfrage als Parameter in Textform
entgegen und liefert das Ergebnis in einem ResultSet-Objekt zurück:
ResultSet re s ult =
stm t . e x e c u t e Q u e r y ( ”SELECT ∗ FROM s t a f f ” ) ;
8
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
3 Die Phasen im Detail
..
......
......
......
......
..
......
......
......
......
Applikationslogik
....
......
......
......
.....
pp p p p p
ppppppppppp
p pp p p p p p p p
p p ppp
p p p p p ppp
pp p p
p
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .p p.pp p. . . . . . . . . . .pp.p . . . . . . . . . . . . . . . . . . . . . . . . . . . .
................................... p p pp
pp p
........ pp
.................
...... pp p
........
ppp
.....
... p p p
.....
p
result
... pp pp
.....
....
p
.
........
.
.
p
.
.
.
pppp pppp
...
................
......................................
ppp pppp
p
p
ppp p pppppp
...
...
.........
.........
.........
.........
...............................................................
.........
.........
..........
......
......
..
.....
qqqqqqqqqqqqqq............ stmt ...............
.
..............
...........................p.p.....................
Sybase-Treiber
p
p
p
...
.........
ppppppp pppppp
.........
.........
pp
pp p
qqq
pp
ppp
ppp
pp
ppp
ppp
p pp
pp
ppp
pp
p
p
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .qq. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .pp. . . . . . . . .
q
p
ppp
q
q
p
ppp
pp p
qqq qqqq
pp
pp
p
...
p
pp
p
p
....
...
..
..............................................
pp
p pp
............
........
p
........
p
.....
p
.
.
.
p
p
.
...
qqqq
...
pp
..
.....
ppp p
...
....
pp p p p
....
......
p pp p p
......
.........
pp p p p p
.........
..................
p pp p p p
p
p
.................................
p
p p p p pp p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p
p
p
p
p
p
pp
p p p pp p p p p p p p p
p p p p p p p p pp p p p p p p pp p p
ppppppppp pppppp ppppp pppppp ppppppppppppp pppppppppppppppppppppppppppppppppp
Sybase
SELECT * FROM staff
......
......
......
......
.......
.......
...........
...................................
Updates entsprechen den drei DML-Anweisungen insert, update und delete. Sie
werden über die executeUpdate-Methode des Statement-Objekts ausgeführt. Diese
Methode liefert als Ergebnis die Anzahl der durch das Update betroffenen Tupel
zurück, vorausgesetzt der Treiber sowie das DBMS unterstützen dies:
stmt . executeUpdate (
”UPDATE s t a f f SET s a l a r y =3000 WHERE name=’ Joe Hacker ’ ” ) ;
....
......
......
....
......
......
Applikationslogik
....
......
.....
.....
.....
....
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........ . . . . . . . . . . . . . . . .
...
...
...
...
..
........
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
..
..
.........
.........
............................................
.
.
.
.
.
.
...
.....
...
........
..........................................
...
.
...
.........
..
.........
...
.
..
..
...
...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . . . . . . . . . . .
.
.
.
..
...
..
...
.......
....
................ .....................
....
...
......
.....
.
.
.....
.
.
.
.
.
.
......
......
......
..............
........
.........................
.........
............
.......................................
Sybase-Treiber
ppppppppp
stmt
ppp
pp p
pp ppp
ppp
Sybase
......
..
..........
.......
.............................
3.5
UPDATE staff SET salary=3000
WHERE name=’Joe Hacker’
Auswertung der Ergebnisse
Wurde eine Anfrage ausgeführt, muss in dieser Phase das zurückgelieferte ResultSet
ausgewertet werden. Dies geschieht nach dem Iterator-Prinzip. Das Objekt besitzt
einen internen Zeiger auf das jeweils aktuelle Tupel der Ergebnismenge. Über die Methode next() wird dieser Zeiger auf das jeweils nächste Tupel gesetzt. Ist kein Tupel
mehr vorhanden, so liefert die next-Methode den boolschen Wert false zurück.
Auf die einzelnen Attribute des aktuellen Tupels kann über die getXXX-Methoden
des ResultSet-Objekts zugegriffen werden. XXX steht dabei für die Namen der Standarddatentypen, z.B. String oder Double. Diese Methoden erwarten entweder den
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
9
4 Ein zusammenhängendes Beispiel
JDBC-Grundlagen
Index des Attributs (Achtung: die Zählung beginnt bei 1!) oder dessen Namen.
Es wird vorausgesetzt, dass der Typ des jeweiligen Attributs bekannt ist.
while ( r e s u l t . next ( ) )
{
System . o u t . p r i n t l n (
r e s u l t . g e t S t r i n g ( ”name ”)+ ” : ”+
Double . t o S t r i n g ( r e s u l t . g e t D o u b l e ( ” s a l a r y ” ) ) ) ;
}
3.6
Schließen der Verbindung
Wird eine Datenbank-Verbindung nicht mehr benötigt, kann sie durch einen Aufruf
der close-Methode des Connection-Objekts geschlossen werden, um Systemressourcen freizugeben:
conn . c l o s e ( ) ;
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
....
.........
.........
.........
....
.........
.........
.........
Sybase-Treiber
....
.........
.........
.........
..........................................................................................................................................
.........................................
..............
........
........
......
......
...
...
..
.....
...
....
...
......
......
.
.........
.
.
.
.
.
.
....................
...
..............................
Sybase
......
......
......
.......
......
...........
.......
..................................
4
Ein zusammenhängendes Beispiel
Nachfolgend sind die Codebeispiele des letzten Abschnitts nochmal in einem Block
zusammengefasst:
// I m p o r t d e r I n t e r f a c e s d e s j a v a . s q l −P a c k a g e s
import j a v a . s q l . ∗ ;
import j a v a . u t i l . P r o p e r t i e s ;
p u b l i c c l a s s JDBCMain
{
10
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
4 Ein zusammenhängendes Beispiel
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] )
{
try
{
// Laden d e s Sybase −T r e i b e r s
C l a s s . forName ( ”com . s y b a s e . j d b c 2 . j d b c . S y b D r i v e r ” ) ;
}
catch ( C l a s s N o t F o u n d E x c e p t i o n e )
{
e . printStackTrace () ;
System . e r r . p r i n t l n ( ”T r e i b e r n i c h t g e f u n d e n ! ” ) ;
System . e x i t ( −1);
}
try
{
P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ;
// Das s o l l t e n a t u e r l i c h vom N u t z e r a b g e f r a g t werden !
p r o p s . pu t ( ”u s e r ” , ”j o e ” ) ;
p r o p s . pu t ( ”p a s s w o r d ” , ”f o o ” ) ;
p r o p s . pu t ( ”s e r v i c e n a m e ” , ”P e r s o n a l ” ) ;
S t r i n g u r l = ”j d b c : s y b a s e : Tds : d b s e r v e r : 1 2 3 4 ” ;
// O e f f n e n d e r V e r b i n d u n g zum DBMS
C o n n e c t i o n conn = D r i v e r M a n a g e r . g e t C o n n e c t i o n ( u r l , p r o p s ) ;
// E r z e u g e n e i n e s S t a t e m e n t s
S t a t e m e n t stmt=conn . c r e a t e S t a t e m e n t ( ) ;
// A u s f u e h r e n e i n e s U p d a t e s
String sql =
”UPDATE s t a f f SET s a l a r y =3000 WHERE name=’ Joe Hacker ’ ” ;
s tm t . e x e c u t e U p d a t e ( s q l ) ;
// A u s f u e h r e n e i n e r A n f r a g e
s q l = ”SELECT ∗ FROM s t a f f ” ;
R e s u l t S e t r e s u l t = stmt . e x e c u t e Q u e r y ( s q l ) ;
// A u s w e r t e n d e r A n f r a g e −E r g e b n i s s e
while ( r e s u l t . next ( ) )
{
System . o u t . p r i n t l n (
r e s u l t . g e t S t r i n g ( ”name ”)+ ” : ”+
Double . t o S t r i n g ( r e s u l t . g e t D o u b l e ( ” s a l a r y ” ) ) ) ;
}
// Beenden d e r V e r b i n d u n g
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
11
5 Weitergehende Möglichkeiten mit JDBC
JDBC-Grundlagen
conn . c l o s e ( ) ;
}
catch ( E x c e p t i o n e )
{
// Ausgabe d e r F e h l e r m e l d u n g
e . printStackTrace ( ) ;
System . e x i t ( −1);
}
}
}
5
Weitergehende Möglichkeiten mit JDBC
Die Möglichkeiten von JDBC gehen weit über die hier vorgestellten Grundlagen
hinaus. Dieser Abschnitt stellt als Beispiele einige fortgeschrittene Techniken vor:
Abfrage der Schema-Information, die Bearbeitung von Ergebnismengen und Transaktionen.
5.1
Nutzung von Metadaten
Bisher wurde vorausgesetzt, dass der Programmierer das Schema der Datenbank
genau kennt. Wenn z.B. der Typ eines Attributs eines Tupels der Ergebnismenge
unbekannt ist, weiß der Entwickler nicht, welche getXXX-Methode zu benutzen ist.
Diese Schema-Informationen (Metadaten) sind allerdings im Data Dictionary der
Datenbank gespeichert und können über JDBC abgefragt werden. Metadaten stehen
an zwei Stellen zur Verfügung:
• Connection.getMetaData liefert ein DatabaseMetaData - Objekt zurück, das
Informationen über die Datenbank im Allgemeinen enthält, d.h. die Tabellenstruktur, die gespeicherten Prozeduren, den verwendeten SQL-Dialekt, etc.
• ResultSet.getMetaData liefert ein ResultSetMetaData - Objekt zurück, das
Informationen über die Struktur einer Ergebnismenge enthält, also z.B. Namen
und Typen der Attribute.
Das folgende Code-Fragment (aufbauend auf der oben genutzten Personal-Datenbank)
analysiert die Attribut-Struktur der Ergebnismenge einer Anfrage:
12
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
5 Weitergehende Möglichkeiten mit JDBC
/∗ . . . ∗/
// A n f r a g e a u s f u e h r e n
R e s u l t S e t r e s u l t = stmt . e x e c u t e Q u e r y ( ”SELECT ∗ FROM s t a f f ” ) ;
// Metadaten a u s l e s e n
R e s u l t S e t M e t a D a t a md = r e s u l t . getMetaData ( ) ;
// Ausgabe a l l e r A t t r i b u t n a m e n
// ACHTUNG : d a s e r s t e A t t r i b u t h a t d i e P o s i t i o n 1 !
f o r ( i n t i d x = 1 ; i d x <=md . getColumnCount ( ) ; i d x ++)
{
System . o u t . p r i n t l n (md . getColumnName ( i d x ) ) ;
}
/∗ . . . ∗/
5.2
Verarbeitung von Ergebnismengen
Ein normales ResultSet-Objekt hat zwei einschränkende Eigenschaften:
• Die Werte können nicht verändert werden.
• Sie besitzen ein sogenanntes forward-only-Cursor, d.h. die Menge kann nur
genau einmal vom ersten bis zum letzten Element durchlaufen werden.
Seit JDBC Version 2.0 existieren scrollbare ResultSets. Mittels diverser Navigationsmethoden kann der Zeiger innerhalb der Menge beliebig gesetzt werden: auf
absolute Positionen, vorwärts oder rückwärts.
Außerdem ist es wünschenswert, wenn man die Daten eines ResultSets nachbearbeiten kann. Zu diesem Zweck existieren änderbare ResultSet-Objekte mit updateXXXMethoden.
Der Typ eines ResultSets wird durch das Statement bestimmt, in dessen Kontext es
erzeugt wird. Ein Statement, das mittels conn.createStatement() erzeugt wurde,
generiert stets nicht veränderbare und nicht scrollbare ResultSets. Werden der
Methode zwei Parameter übergeben, lässt sich dieses Verhalten ändern:
S t a t e m e n t stmt =
conn . c r e a t e S t a t e m e n t ( i n t r e s u l t S e t T y p e ,
int resultSetConcurrency );
Der Parameter resultSetType kann folgende Werte annehmen:
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
13
5 Weitergehende Möglichkeiten mit JDBC
resultSetType
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE
JDBC-Grundlagen
Bedeutung
Das ResultSet kann nur einmal vom ersten bis zum letzten Element durchlaufen
werden.
Das ResultSet ist scrollbar, simultane
Änderungen anderer Nutzer bleiben verborgen
Das ResultSet ist scrollbar, Änderungen
anderer Nutzer schlagen auf die Werte
durch.
Für resultSetConcurrency gibt es diese Möglichkeiten:
resultSetConcurrency
ResultSet.CONCUR_READ_ONLY
ResultSet.CONCUR_UPDATABLE
Bedeutung
Das Ergebnis kann nicht verändert werden.
Das Ergebnis kann editiert werden.
Das folgende Code-Fragment erzeugt ein Statement für scrollbare und änderbare
ResultSets:
/∗ . . . ∗/
S t a t e m e n t s tmt =
conn . c r e a t e S t a t e m e n t ( R e s u l t S e t . TYPE SCROLL INSENSITIVE ,
R e s u l t S e t . CONCUR UPDATABLE ) ;
/∗ . . . ∗/
// a u s f u e h r e n e i n e r A n f r a g e
ResultSet re s ult =
stm t . e x e c u t e Q u e r y ( ”SELECT ∗ FROM s t a f f ” ) ;
// s e t z t den Z e i g e r a u f P o s i t i o n 2
result . absolute (2);
// s e t z t den Z e i g e r a u f d a s e r s t e T u p e l
result . first ();
// a e n d e r t d a s G e h a l t
r e s u l t . updateDouble ( ”s a l a r y ” ,2000);
5.3
Transaktionen
Die JDBC-API unterstützt die Nutzung von Transaktionen. Standardmäßig ist definiert, dass jede SQL-Anweisung, die per executeQuery oder executeUpdate ausgeführt wird, einer Transaktion entspricht. Dieses Verhalten lässt sich über die
setAutoCommit-Methode des Connection-Objekts ändern. Durch den Parameter
14
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
6 JDBC und Applets
false wird nach Ausführung von executeXXX-Methoden ein expliziter Aufruf von
Connection.commit bzw. Connection.rollback erwartet:
/∗ . . . ∗/
// e i n e T r a n s a k t i o n f u e r s i c h
stmt . executeUpdate (
”UPDATE s t a f f SET s a l a r y =3000 WHERE name=’ Joe Hacker ’ ” ) ;
conn . setAutoCommit ( f a l s e ) ;
/∗ ∗∗∗
∗ Beginn der T r a n s a k t i o n
∗∗∗ ∗/
stmt . executeUpdate (
”DELETE FROM s t a f f WHERE name=’ A l f Weise ’ ” ) ;
stmt . executeUpdate (
”INSERT INTO s t a f f ( name , s a l a r y ) VALUES ( ’ Tina K u n t e r b u n t ’ , 1 0 0 0 ) ” ) ;
// Commit
conn . commit ( ) ;
/∗ ∗∗∗
∗ Ende d e r T r a n s a k t i o n
∗∗∗ ∗/
/∗ ∗∗∗
∗ B e g i n n e i n e r neuen T r a n s a k t i o n
∗∗∗ ∗/
stmt . executeUpdate (
”UPDATE s t a f f SET s a l a r y =2000 WHERE name=’ Tina K u n t e r b u n t ’ ” ) ;
// R o l l b a c k
conn . r o l l b a c k ( ) ;
/∗ ∗∗∗
∗ Ende d e r T r a n s a k t i o n
∗∗∗ ∗/
/∗ . . . ∗/
Hinweis: Das zugrunde liegende DBMS muss natürlich Transaktionen unterstützen!
6
JDBC und Applets
Es existieren zwei verschiedene Anwendungsbereiche für Java: Applikationen, die als
normale“ Programme auf einem Rechner laufen und Applets, deren Code von einem
”
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
15
6 JDBC und Applets
JDBC-Grundlagen
dbserver
ppppp
ppppp
pp pp
ppppp
p
p
p
p
p
ppppp
pppp
ppppp
ppp pp
JDBCTreiber
Port
1234
Sybase
Datenbankserver
pp verboten
pppp p
ppp pp
pp ppp
p
p
p
p
ppppp
pppp p
ppp pp
pp ppp
p
p
p
p
pppp
Client
Applet
pppppppp
pppppppp
p ppppppp
ppppppppppppppp
ppppppppppppppp
ppppppppppppppp
ppppppppppppppp
ppppppppppppppp
ppppppppppppppp
Port
ppppppppppppppp
pppppppppp
80
www
Apache
Webserver
Abbildung 3: direkter JDBC-Zugriff (verboten)
www
Client
pppppppp
Applet
JDBCTreiber
pppppppp
ppppp ppppppppppppp
ppppppppppppppppppppppppppppppp
pppppppppppppppppppppppppp pppp
pppppppppppppppp pppppppppppppp
ppppppppppppppppppppppppppppppppppppppppp
ppppppppppppppppppppppppppppppppppppppppp
pppppppppppppppppppppppppppp
Port
Apache
80
Webserver
pppppppp Port
Sybase
1234 Datenbankserver
Abbildung 4: Web- und Datenbankserver auf einem Rechner
anderen Rechner geladen wird und deshalb bestimmten Sicherheitsanforderungen
genügen muss.
Eine wichtige Einschränkung ist, dass ein Applet nur Daten von dem Rechner lesen
darf, von dem aus es geladen wurde. Der Zugriff auf die lokalen Daten des Clienten
sind verboten, außerdem darf das Applet keine Verbindungen zu anderen Rechnern
aufbauen. Die Konsequenz für ein JDBC-nutzendes Applet zeigt Abbildung 3: wenn
das Applet vom Rechner namens www geladen wurde, ist keine direkte Datenbankverbindung zum Rechner dbserver möglich.
Es bestehen zwei Möglichkeiten, dieses Problem zu lösen. Zum Ersten sind Datenbankzugriffe gestattet, wenn sich der Datenbankserver auf demselben Rechner
befindet wie der Webserver, siehe Abbildung 4. Diese Konstellation hat allerdings
einige Nachteile: die Last des Webservers und des Datenbankservers konzentrieren
sich auf einen gemeinsamen Rechner. Außerdem lässt sich der Datenbankserver nur
schlecht abschirmen, wenn z.B. nur Zugriffe aus dem Intranet erlaubt sein sollen.
Aus diesem Grund wird oftmals die zweite Lösung favorisiert, siehe Abbildung 5.
Auf dem Webserver wird ein Gateway eingerichtet. Dieses Gateway hat die Aufgabe,
16
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
JDBC-Grundlagen
7 Weiterführende Lektüre
www
Client
Applet
JDBCTreiber
pppppppp
pppppppp
pppppppp
ppppppppppppp pppppppp
ppppppp pppppppppppppp
p pppppppppppppppppppp
ppppppppppppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
pppppppppppp
p
Port
80
Apache
Webserver
pppppppp
Gateway
p
pp pp
dbserver
pppppppp Port
Sybase
1234 Datenbankserver
Abbildung 5: JDBC-Zugriff über ein Gateway
Anfragen von außen entgegenzunehmen, evtl. vorzuverarbeiten und die Datenbankzugriffe an den eigentlichen Server weiterzuleiten.
Ein weiteres Problem ist der JDBC-Treiber an sich. Zur Erinnerung: Applets sind
Programme, die auf einem Client-Rechner ausgeführt werden. Ein JDBC-Treiber ist
nichts weiter als eine Menge von Java-Klassen, deren Code ebenfalls auf dem Clienten
ausgeführt wird. Aus Sicherheitsgründen sind deshalb nicht alle JDBC-Treiber für
den Einsatz in Applets geeignet. An dieser Stelle sei allerdings auf weiterführende
Literatur verwiesen.
7
Weiterführende Lektüre
Im WWW sind eine Vielzahl von Dokumenten über den Gebrauch von JDBC verfügbar, z.B.:
• Java-API Dokumentation:
http://java.sun.com/products/jdk/1.4.2/docs/api/index.html
• JDBC-Tutorial von Sun:
http://java.sun.com/docs/books/tutorial/jdbc/
• ein weiteres Sun-Tutorial:
http://developer.java.sun.com/developer/Books/JDBCTutorial/
• Kurzübersicht:
http://www.cs.unc.edu/Courses/wwwp-s98/members/thornett/jdbc/
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
17
7 Weiterführende Lektüre
JDBC-Grundlagen
• Code-Beispiele für Java allgemein:
http://javaalmanac.com/
• Ein JDBC-Seminar:
http://www.informatik.uni-stuttgart.de/ipvr/as/lehre/seminar/docss02/
JDBC-Seminar.pdf
• ...
18
SS 2003 Gunar Fiedler, LS DBIS, BTU Cottbus
Herunterladen