Datenbankzugriff über JDBC - Technologie der Informationssysteme

Werbung
Datenbankzugriff über JDBC
Content
..
.......
... .....
...
...
..
...
...
...
...
...
...
...
...
...
.
...
..
...
...
.
.
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
..
Information
Concept
Topic
Datenbanken I (Systemorientierte Informatik IV)
SS 2007
Gunar Fiedler ([email protected])
Institut für Informatik
Arbeitsgruppe Technologie der Informationssysteme“
”
Christian-Albrechts-Universität zu Kiel
1 Einführung
Mit SQL existiert eine standardisierte Sprache, um auf Daten eines relationalen Datenbanksystems zuzugreifen. Die Art und Weise, wie SQL-Anfragen an das System
übermittelt werden, ist jedoch für jedes Datenbankmanagementsystem spezifisch.
Oftmals unterscheiden sich sogar verschiedene Versionen desselben DBMS in den
verwendeten Schnittstellen.
Eine Anwendung, die auf ein DBS zugreifen möchte, muss die Kommunikationsprotokolle des DBMS kennen. Die Hersteller bieten deshalb für die gängigen Programmiersprachen und Laufzeitumgebungen Bibliotheken an, die den Datenbankzugriff
ermöglichen. In PHP kann man beispielsweise auf eine MySQL-Datenbank folgendermaßen zugreifen (die Variablen sind selbsterklärend, die Fehlerbehandlung wurde
weggelassen):
$conn = mysql_connect($host,$user,$password);
mysql_select_db($db,$conn);
$result = mysql_query("select HOTEL_CODE,HOTEL_NAME from ACCOMMODATION");
while($row = mysql_fetch_row($result))
{
echo "Code: $row[0], Name: $row[1]<br />";
}
mysql_close($conn);
Wenn diese Anwendung z.B. nach PostgreSQL portiert werden soll, so müssen alle
mysql_*-Aufrufe z.B. durch entsprechende pg_*-Aufrufe des PostgreSQL-Moduls
ersetzt werden.
Um anwendungsseitig einen (relativ) DBMS-neutralen Zugriffsmechanismus auf Datenbanken zu ermöglichen, wurden diverse Frameworks spezifiziert, z.B. die Open
Database Connectivity (ODBC), ActiveX Data Objects (ADO) oder die Java Database Connectivity (JDBC). Mit letzterem wollen wir uns hier beschäftigen.
Um ein mögliches Missverständnis auszuschließen: JDBC ist kein Framework, dass
die systemspezifische Unterstützung verschiedener SQL-Dialekte abstrahiert. Die
2 Grundgerüst eines JDBC-basierten Programms
Datenbankzugriff über JDBC
JDBC-Infrastruktur sorgt lediglich dafür, dass eine SQL-Anfrage von der Anwendung standardisiert an das DBS übergeben und das Ergebnis zurückgeliefert wird.
JDBC sorgt nicht dafür, dass z.B. die in MySQL optionale from-Klausel beim Zugriff
auf andere Systeme automatisch ergänzt wird. SQL Tuning“ für spezifische Systeme
”
bleibt weiterhin Aufgabe des Programmierers.
2 Grundgerüst eines JDBC-basierten Programms
Abbildung 1 zeigt den Grobaufbau einer JDBC-basierten Anwendung. Sie besteht
aus 3 Schichten:
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
.
......
......
......
......
JDBCTreiber
..
......
......
......
......
.
......
......
......
......
JDBCTreiber
.
......
......
......
......
..
......
......
......
......
.
......
......
......
......
JDBCTreiber
.
......
......
......
......
.
......
......
......
......
..
......
......
......
......
..
......
......
......
......
ODBCTreiber
..
......
......
......
......
..........................................................................................................................................
..
........................ ................................
.........
......
......
.....
....
...
.....
...
....
...
......
......
.........
........
.
.
..................
.
.
.
.
.
.
.
.
.
.
.......................
DB2
......
......
......
......
.......
.......
...........
..................................
..
........................ ................................
.........
......
......
.....
....
...
.....
...
....
...
......
......
.........
........
.
.
..................
.
.
.
.
.
.
.
.
.
.
.......................
Oracle
......
......
......
......
.......
.......
...........
..................................
..........................................................
.........
......
......
.....
....
...
.....
..
....
....
......
.....
.........
........
.
.
..................
.
.
.
.
.
.
.
.
.
.
........................
CSV-Datei
......
......
......
......
.......
.......
...........
..................................
Abbildung 1: Aufbau einer JDBC-basierten Anwendung
• Anwendungslogik: Sie definiert die Verarbeitungsregeln der Geschäftsprozesse.
• JDBC-Datenbanktreiber: Er kapselt die Spezifika des Datenbanksystems
und stellt der Anwendungslogik 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.
2
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
2 Grundgerüst eines JDBC-basierten Programms
Aus Sicht des Java-Programmierers ist ein JDBC-Datenbanktreiber eine Bibliothek
bestehend aus einer Reihe von Klassen. Die Klassen implementieren die Interfaces
der Standard-Packages java.sql und javax.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.
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.
ppppp
Laden des Treibers
pppppppp
ppppp
Herstellen der Verbindung
zum DBMS
ppppppppp
pppppp
Erzeugen eines
Statement-Objekts
ppppppppp
ppppppppppppppp
pppppppppw
p
p
p
p
ppppppppppppppp
p
p
p
p
p
p
p
p
pppp
ppppppppppppppp
pp pppppppppp
p
ppppppppppppppp
p
p
p
p
p
p
p
p
p
p
p
pp
ppppppppppppppp
p
p
p
p
p
p
p
p
p
p
p
p
ppppppppppppppp
ppp
p
p
p
p
p
p
p
p
p
p
ppppppppppppppp
p
p
ppppppppppppppp
pppp ppppp ppppppppppppp
Ausführen
einer Anfrage
w
Ausführen
eines Updates
ppppp
Auswertung
der Ergebnisse
p
pppp ppp
pppppppppp
ppp ppppppppp
pppppppppp
pp pppppppppp
pppppppppp
p
p
p
p
p
p
p
p
p
p
p
pppppppppp
ppppp
pppppppppp
pppp pppppppp
pppppppppp
ppp ppppppppp
pppppppppp
pp pppppppppp
p
p
p
p
p
p
pppppppppp
p
p
p
p
p
pppp
pppppppppp
ppp ppppppppp
ppppppppppw
pp pppppppppp
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
SS 2007, Gunar Fiedler, ISE@CAU
3
3 Die Phasen im Detail
Datenbankzugriff über JDBC
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 eine 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
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
..
......
......
......
......
DB2-Treiber
..
......
......
......
......
..........................................................................................................................................
.......................................
...............
........
......
........
....
......
...
...
....
....
...
......
....
.........
......
..................
.........
.................................
DB2
......
.
.....
......
.......
......
...........
.......
..................................
3.1 Laden des Treibers
Wie bereits angedeutet, ist ein JDBC-Datenbanktreiber nichts anderes als eine Bibliothek diverser Java-Klassen, welche die Interfaces aus java.sql und javax.sql
4
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
3 Die Phasen im Detail
implementieren. Jeder Treiber enthält als Repräsentanten eine Hauptklasse“, die
”
das Interface java.sql.Driver implementiert. Ü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.
Das dynamische Laden eines Treibers gestaltet sich genauso wie das Laden jeder anderen beliebigen Java-Klasse. Angenommen, wir möchten den Treiber für
DB2-Datenbanken laden. Die Hauptklasse“ des JDBC-Treibers hat den Namen
”
com.ibm.db2.jcc.DB2Driver:
try
{
C l a s s . forName ( ”com . ibm . db2 . j c c . DB2Driver ” ) . n e w I n s t a n c e ( ) ;
}
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 Anwendung zur Verfügung:
.
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
..
......
......
......
......
..
......
......
......
......
DB2-Treiber
..
......
......
......
......
..........................................................................................................................................
.................................
..................
.........
.........
......
......
....
....
...
.....
.
....
...
......
.....
.........
.......
.
.
.
.
.
.
..................
.
.
.
.
.............................
DB2
......
......
......
......
.......
...........
.......
..................................
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:
SS 2007, Gunar Fiedler, ISE@CAU
5
3 Die Phasen im Detail
Datenbankzugriff über JDBC
• 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?
• ...
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 DB2-Treiber erwartet
beispielsweise folgende URL:
jdbc:db2://<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 Doppelpunkt angegeben
werden. Für Verbindungsparameter sei auf das DB2-Handbuch verwiesen.
Angenommen, der Nutzer joe (Passwort: foo) möchte die DB2-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 : db2 : / / 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:
6
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
3 Die Phasen im Detail
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 ” ) ;
S t r i n g u r l = ”j d b c : db2 : / / 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 =
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 : db2 : / / 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 der
Anwendung und der Datenbank:
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
....
.........
.........
.........
....
.........
.........
.........
DB2-Treiber
....
.........
.........
.........
qqq
qqqq
qqqqq
qqqq
..........................................................................................................................................
...................................
.................
.........
........
......
......
....
....
...
.....
....
...
......
....
.........
.......
.
.
.
.
.
.
.
..................
.
................................
qqqq
DB2
......
.....
......
......
.......
.......
...........
...................................
3.3 Datasources
In realen Umgebungen ist es normalerweise notwendig, den Verbindungsaufbau weiter zu abstrahieren. In der URL sind z.B. der Datenbankserver und der Name der
Datenbank vermerkt. Eine Anwendung wird i.d.R. in verschiedenen Umgebungen
eingesetzt, und es kann relativ häufig passieren, dass sich die Konfigurationsparameter der Datenbank ändern. Außerdem ist vielleicht eine zentrale Konfiguration
SS 2007, Gunar Fiedler, ISE@CAU
7
3 Die Phasen im Detail
Datenbankzugriff über JDBC
für verschiedene Anwendungen sinnvoll, die alle parallel auf ein Datenbanksystem
zugreifen möchten.
Seit der JDBC-Version 2.0 existiert ein neues Interface namens javax.sql.DataSource,
welches sich dieses Problems annimmt. DataSource-Objekte kapseln eine Datenquelle. Über die Methode getConnection des DataSource-Interfaces kann man sich eine
vorkonfigurierte Verbindung zu dieser Datenquelle geben lassen. DataSources spielen ihre Vorteile insbesondere in J2EE-Umgebungen aus. Dort übernimmt der Anwendungsserver die zentrale Verwaltung aller bekannten Datenquellen. Über einen
Verzeichnisdienst (JNDI, Gelbe Seiten“) kann eine Anwendung auf eine Datenquelle
”
des Anwendungsservers über einen Namen zugreifen. Wenn sich die physischen Parameter der Datenquelle ändern (z.B. wenn die Datenbank auf einen neuen Rechner
umzieht), dann muss diese Änderung nur zentral im Anwendungsserver durchgeführt
werden.
Die Benutzung von Datenquellen hat einen weiteren entscheidenden Vorteil: das
Öffnen einer Verbindung ist ein relativ kostenintensiver Prozess, der einige Sekunden dauern kann. Die zentrale Verwaltung von Datenbankverbindungen erlaubt die
Implementierung des Pooling“-Patterns: Die Datenquelle verwaltet einen Pool von
”
offenen Verbindungen. Wenn eine Anwendung eine Verbindung anfordert, dann wird
keine neue Verbindung geöffnet, sondern sie bekommt eine der offenen Verbindungen
zugeteilt, die sich im Pool befinden. Wenn die Anwendung die Verbindung schließt,
dann wird die Verbindung wieder als frei“ markiert. Durch diesen Mechanismus,
”
der einigen vielleicht aus dem Kontext von Prozessen und Threads bekannt ist, wird
eine erhebliche Performance-Steigerung erreicht.
3.4 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 ( ) ;
8
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
3 Die Phasen im Detail
..
......
......
......
......
..
......
......
......
......
Applikationslogik
..
......
......
......
......
..........................................................................................................................................
...
.........
.........
.........
...
.........
.........
.........
DB2-Treiber
.................................................
..............
........
.......
.....
.....
..
..
....
.......
.............
....................................................
qqqqqqqqqqqqqq................
stmt
...
.........
.........
.........
qqq
qqq
qqqqq
qqqq
..........................................................................................................................................
..
........................ ................................
......
.........
.....
......
....
...
.....
.
....
...
......
....
.........
......
.
.
.
.
.
.
.
.
..................
.................................
qqqq
DB2
......
......
......
......
.......
.......
...........
...................................
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 mit diesem Statement-Objekt eine neue Anfrage gestellt wird.
3.5 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 =
s t m t . e x e c u t e Q u e r y ( ”SELECT ∗ FROM s t a f f ” ) ;
SS 2007, Gunar Fiedler, ISE@CAU
9
3 Die Phasen im Detail
Datenbankzugriff über JDBC
..
......
......
......
......
..
......
......
......
......
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.....................
DB2-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 p pp 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
DB2
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:
stm t . e x e c u t e U p d a t e (
”UPDATE s t a f f SET s a l a r y =3000 WHERE name=’ Joe Hacker ’ ” ) ;
...
......
......
....
......
......
Applikationslogik
....
.....
......
.....
.....
....
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........ . . . . . . . . . . . . . . . .
...
...
...
...
..
.......
.
.
.
.........
.........
........................
.
.
.
.
.
.
.
.
.
.
.
.
.
.........
.........
.
.
.
......
.....
..
.....
........ stmt .........
...................................
DB2-Treiber
...
.
.
.
.
.
...
.
.
.
.
..
.........
...
.
..
...
...
...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...... . . . . . . . . . . . . .
.
.
..
..
..
...
...
.......
....
................ .....................
....
......
...
.
.
.
.
.....
.
.
.....
......
...
......
............
......
........
............................
.........
............
.......................................
ppppppppp
ppp
ppp
ppppp
pp
DB2
......
..
..........
.......
.............................
UPDATE staff SET salary=3000
WHERE name=’Joe Hacker’
3.6 Auswertung der Ergebnisse
Wurde eine Anfrage ausgeführt, muss in dieser Phase das zurückgelieferte ResultSet
ausgewertet werden. Dies geschieht nach dem Iterator-Pattern. 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. Zu
Beginn steht der Zeiger vor dem ersten Tupel.
10
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
4 Ein zusammenhängendes Beispiel
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
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.7 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. Gleiches gilt für Resultsets und Statements:
result . close ();
stmt . c l o s e ( ) ;
conn . c l o s e ( ) ;
..
......
......
......
......
.
......
......
......
......
Applikationslogik
.
......
......
......
......
..........................................................................................................................................
....
.........
.........
.........
....
.........
.........
.........
DB2-Treiber
...
.........
.........
.........
..........................................................................................................................................
...................................
.................
.........
........
......
......
....
....
...
.....
.
....
...
......
.....
.........
.......
.
.
.
.
.
..................
.
.
.
.
.
............................
DB2
......
.
......
.....
.......
......
...........
.......
..................................
Man sollte sich angewöhnen, jedes Resultset, jedes Statement und jede Verbindung
explizit zu schließen und sich nicht auf den Garbage-Collector der JVM verlassen.
4 Ein zusammenhängendes Beispiel
Nachfolgend sind die Codebeispiele des letzten Abschnitts nochmal in einem Block
zusammengefasst:
SS 2007, Gunar Fiedler, ISE@CAU
11
4 Ein zusammenhängendes Beispiel
Datenbankzugriff über JDBC
// 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
{
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 DB2−T r e i b e r s
C l a s s . forName ( ”com . ibm . db2 . j c c . DB2Driver ” ) . n e w I n s t a n c e ( ) ;
}
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
{
S t r i n g u r l = ”j d b c : db2 : / / d b s e r v e r : 1 2 3 4 / P e r s o n a l ” ;
// O e f f n e n d e r V e r b i n d u n g zum DBMS
// Nutzername und P a s s w o r t s o l l t e n 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 !
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 ” ) ;
// 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 ’ ” ;
stm 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 = s tm t . 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 ” ) ) ) ;
}
result . close ();
12
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
5 Weitergehende Möglichkeiten mit JDBC
s tmt . c l o s e ( ) ;
// Beenden d e r V e r b i n d u n g
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, sofern der Treiber
und das DBMS dies unterstützen. 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:
SS 2007, Gunar Fiedler, ISE@CAU
13
5 Weitergehende Möglichkeiten mit JDBC
Datenbankzugriff über 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 = stm t . 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-Cursor1 , 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:
1
Cursor steht hier für current set of records.
14
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
5 Weitergehende Möglichkeiten mit JDBC
resultSetType
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE
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 stmt =
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 =
s t m 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
SS 2007, Gunar Fiedler, ISE@CAU
15
6 Weiterführende Lektüre
Datenbankzugriff über JDBC
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
stm t . e x e c u t e U p d a t e (
”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
∗∗∗ ∗/
stm t . e x e c u t e U p d a t e (
”DELETE FROM s t a f f WHERE name=’ A l f Weise ’ ” ) ;
stm t . e x e c u t e U p d a t e (
”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
∗∗∗ ∗/
stm t . e x e c u t e U p d a t e (
”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 Weiterführende Lektüre
Im WWW sind eine Vielzahl von Dokumenten über den Gebrauch von JDBC verfügbar, z.B.:
16
SS 2007, Gunar Fiedler, ISE@CAU
Datenbankzugriff über JDBC
6 Weiterführende Lektüre
• 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/
• Code-Beispiele für Java allgemein:
http://www.exampledepot.com/
• ...
SS 2007, Gunar Fiedler, ISE@CAU
17
Herunterladen