20.7 Mit Java an eine Datenbank andocken
 
Die Verbindung zu einer Datenbank wird über die Klasse DriverManager und die Schnittstelle Connection aufgebaut. Alle verwendeten Pakete liegen unter java.sql.*. Vor der Ausführung der JDBC-Befehle muss ein passender Datenbanktreiber geladen werden.
20.7.1 Der Treibermanager
 
Alle Datenbanktreiber müssen an einer Stelle, dem Treibermanager, gesammelt werden. Dazu dient eine besondere Java-Klasse, die Klasse DriverManager. Alle Methoden der Klasse sind statisch, da sich ein Exemplar dieser Klasse nicht erzeugen lässt; der Konstruktor ist privat. Die wichtigste Methode des Treibermanagers ist getConnection(), mit der wir eine Verbindung zur Datenbank aufbauen können. Es lassen sich aber auch alle angemeldeten Treiber erfragen.
 Hier klicken, um das Bild zu Vergrößern
20.7.2 Den Treiber laden
 
Der Datenbanktreiber ist Java-Klasse, die sich beim Einbinden in die JVM automatisch beim Treibermanager anmeldet. Unsere erste Aufgabe ist es, die Treiber-Klasse zu laden, sodass das Treiber-Objekt gebildet und beim Manager eingetragen werden kann. Zwei Möglichkeiten sind populär. Die erste: Der Treiber wird in der Kommandozeile über den Schalter »-D« eingebunden. Dazu setzen wir mit der Eigenschaft jdbc.drivers einen Datenbanktreiber fest.6
java -Djdbc.drivers =sun.jdbc.odbc.JdbcOdbcDriver <Javaklasse>
Die Property jdbc.drivers lässt sich auch in einer externen Datei definieren.
Die zweite Möglichkeit ist die Funktion Class.forName(), die eine Klasse lädt.
final class java.lang. Class<T>
implements Serializable, GenericDeclaration, Type, AnnotatedElement
|
|
static Class forName( String className ) throws ClassNotFoundException
Sucht, lädt und bindet die Klasse mit dem qualifizierten Namen className ins Laufzeitsystem ein. Es wird ein Class-Objekt zurückgegeben, falls die Klasse geladen werden kann, andernfalls wird dies mit einer ClassNotFoundException quittiert. |
Die Programmzeilen für das Laden der JDBC-ODBC-Bridge und der Klasse com.ibm.db2. jcc.DB2Driver sind somit:
Listing 20.5
com/javatutor/insel/jdbc/DriverManagerDemo.java, Ausschnitt
try
{
Class.forName( DatabaseConstants.DRIVER );
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
}
catch ( ClassNotFoundException e )
{
// OO! Treiber konnte nicht geladen werden.
e.printStackTrace();
}
Um die Bindung zu einer Datenbank lose zu halten, haben wir den Klassennamen nicht hart einkodiert, sondern die Klasse DatabaseConstants geschrieben. (Noch besser ist es, aus dem Namensdienst eine DataSource zu nehmen.) Da wir die Klasse nur laden, aber die Referenz auf den Klassen-Deskriptor nicht benötigen, belassen wir es bei einem Aufruf und beachten den Rückgabewert nicht. Diese Methode löst eine ClassNotFoundException aus, falls die Klasse nicht gefunden wurde, der Treiber also nicht geladen werden konnte.
Datenbank
|
Klassenname für den JDBC-Treiber
|
DB2/Derby
|
com.ibm.db2.jcc.DB2Driver
|
Oracle
|
oracle.jdbc.driver.OracleDriver
|
mSQL
|
COM.imaginary.sql.msql.MsqlDriver
|
MySQL
|
com.mysql.jdbc.Driver4
|
Borland JDataStore
|
com.borland.datastore.jdbc.DataStoreDriver
|
Borland Interbase
|
interbase.interclient.Driver
|
Adabas D
|
de.sag.jdbc.adabasd.ADriver
|
SYBASE ASE
|
com.sybase.jdbc.SybDriver
|
IDS Server
|
ids.sql.IDSDriver
|
Hinweis In einigen Programmlistings findet sich die Zeile zum Laden des Treibers, die gleich mit newInstance() ein Objekt des Treibers erzeugt.
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
Das ist im Prinzip nicht nötig, denn Class.forName() sollte die Klasse laden. Es gibt jedoch virtuelle Maschinen, die das Klassenladen aus Geschwindigkeitsgründen vermeiden und dann keine Klassendatei einladen. In solchen Fällen muss der Laufzeitumgebung mit dem Bilden eines Exemplars explizit der Hinweis gegeben werden, dass die Treiber-class-Datei nötig ist, damit sich der Treiber beim Treibermanager anmelden kann.
|
20.7.3 Eine Aufzählung aller Treiber
 
Die statische Funktion getDrivers() der Klasse DriverManager liefert eine Aufzählung der angemeldeten Treiber. Die folgenden Zeilen geben einfach den Klassennamen aus – die Treiber implementieren nicht unbedingt eine sinnvolle toString()-Methode, sodass wir uns mit dem Klassennamen begnügen.1
Listing 20.6
com/javatutor/insel/jdbc/DriverManagerDemo.java, Ausschnitt
for ( Enumeration<Driver> e = DriverManager.getDrivers(); e.hasMoreElements(); )
System.out.println( e.nextElement().getClass().getName() );
Die Elemente, die durch die Enumeration ausgelesen werden, sind Treiber-Objekte vom Typ Driver. Jeder Datenbanktreiber implementiert diese Schnittstelle, doch da wir bisher keinen Treiber geladen haben und ein normales Programm zunächst keinen Datenbank-treiber anmeldet, ist die Ausgabe der oberen Schleife leer.
Laden wir den JDBC-ODBC-Treiber und den Treiber, der hinter der Klasse com.ibm.db2.jcc.DB2Driver steckt, wie oben, dann besteht die Ausgabe aus der folgenden Zeile:
com.ibm.db2.jcc.DB2Driver
sun.jdbc.odbc.JdbcOdbcDriver
20.7.4 Log-Informationen
 
Zu Testzwecken bietet es sich an, Informationen des Treibers und der Datenbank in einen speziellen Ausgabekanal zu schreiben. Wir können die Log-Informationen so umlenken, dass sie in den Standardausgabestrom geschrieben werden. Dazu dient die statische Methode setLogWriter(), die einen PrintWriter als Parameter erwartet. Folgende Zeile gibt alle Informationen auf dem Bildschirm aus, die in das Logbuch geschrieben werden:
DriverManager.setLogWriter( new PrintWriter(System.out) );
Ladevorgang der Treiber protokolliert ausgeben
Eine solche Ausgabe ist hilfreich, da interessante Aussagen über die Funktionsweise der Treiber auf diese Art offenbart werden. Zur Set-Methode existiert die passende getLogWriter()-Methode, die den PrintWriter zurückgibt. Eine Anfrage an getLogWriter() gibt null zurück, was verrät, dass standardmäßig keine Ausgabe stattfindet. Es wird also keine versteckte Datei erzeugt.
Testen wir die Ausgabe, die die beiden Programmzeilen erzeugen:
Listing 20.7
com/javatutor/insel/jdbc/DriverManagerDemo.java2, Ausschnitt
DriverManager.setLogWriter( new PrintWriter(System.out) );
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
Zunächst setzen wir die Ausgabe auf den Standardausgabekanal. Dann laden wir die Treiberklasse für die JDBC-ODBC-Brücke. Die Ausgabe zeigt den eingetragenen Treiber.
JdbcOdbcDriver class loaded
DriverManager.initialize: jdbc.drivers = null
JDBC DriverManager initialized
registerDriver: driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.
JdbcOdbcDriver@757aef]
sun.jdbc.odbc.JdbcOdbcDriver
Die Methode setLogWriter() ist die erste Methode, die die Klasse DriverManager benutzt. Daher bekommt der Klassenlader die Aufgabe, die Klasse DriverManager zu laden. setLogWriter() speichert dann das PrintWriter-Objekt in einer privaten Variablen und macht sonst nichts.
Erst das Laden eines Treibers führt zum Aufruf der statischen initialize()-Methode. Sie führt die private Methode loadInitialDrivers() aus, die zur ersten Ausgabezeile führt. Hier sind noch keine Treiber angemeldet, da in den Eigenschaften »jdbc.drivers« nichts eingetragen ist. Diese Eigenschaft wird in der Regel dann gesetzt, wenn von außen über den Schalter »-D« eine Klasse angesprochen wird. Nach dem Suchen in den Eigenschaften folgt die Ausgabe »JDBC DriverManager initialized«. Nun hat der Treiber die DriverManager-Klasse hochgefahren, und der Treibermanager kann den Treiber anmelden. Er ist vom Typ Driver. Dieser wird zusammen mit dem zugehörigen Class-Objekt und einem Namen in der internen Klasse DriverInfo in einem internen Vector gespeichert. Die Ausgabe »registerDriver:[...]« stammt von der Anmeldung des Treibers. Wir sehen genau die Informationen, die in der Klasse DriverInfo gespeichert sind. Die Ausgabe wird auch von toString() von DriverInfo generiert.
Nicht nur Treiber und SQL-Klassen nutzen den Log-Stream, auch wir können Zeichenketten ausgeben. Dazu dient die statische Methode println(), die als Parameter nur einen String annimmt. println() ist so implementiert, dass bei einem nicht gesetzten Log-Stream die Ausgabe unterbleibt.
20.7.5 Verbindung zur Datenbank
 
Nach dem Laden des Treibers können wir eine Verbindung zur Datenbank mit Hilfe des Connection-Objekts aufbauen, das DriverManager.getConnection() zurückgibt. Der Methode wird eine Datenbank-URL mitgegeben und optional Benutzername und Passwort.
Die Datenquelle angeben
Alle Datenquellen sind durch eine besondere URL qualifiziert, die folgendes Format besitzt:
jdbc:Subprotokoll:Datenquellenname
Datenbank
|
Subprotokoll
|
Beispiel
|
Derby
|
derby:net
|
jdbc:derby:net://localhost:1527/
|
ODBC-Datenquellen
|
odbc
|
jdbc:odbc:Pflanzen
|
mSQL
|
msql
|
jdbc:msql://host:1234/database
|
Interbase
|
interbase
|
jdbc:interbase://localhost/dabase.gdb
|
Oracle Thin
|
oracle:thin
|
jdbc:oracle:thin:@host:1243:database
|
IBM DB2
|
Db2
|
jdbc:db2://database
|
Sybase
|
sybase:Tds
|
jdbc:sybase:Tds:host:1234/database
|
MySQL
|
mysql
|
jdbc:mysql://host/database
|
Verbindung aufnehmen
Die getConnection()-Methode liefert nun ein Connection-Objekt, das mit der Quelle verbunden ist. Die folgende Anweisung verbindet uns mit einer Datenbank, die den Namen »OpenGeoDB« trägt. (Im Fall von ODBC wurde der Name im Datenquellen-Administrator festgelegt und hat nichts mit dem Dateinamen zu tun.)
con = DriverManager.getConnection( "jdbc:derby:net://localhost:1527/OpenGeoDB",
"user",
"pass" );
Die Methode getConnection() erwartet bis zu drei Parameter: Die URL der Datenbank, zu der die Verbindung aufgenommen werden soll, ist der Pflichtparameter. Der Anmeldename und das Passwort sind optional und können auch leere Strings ("") sein, wenn eine Authentifizierung keine Rolle spielt.
Meldet getConnection() keinen Fehler, so liefert sie uns eine geöffnete Datenbankverbindung.
class java.sql. DriverManager
|
|
static Connection getConnection( String url ) throws SQLException
Versucht eine Verbindung zur Datenbank aufzubauen. Die Klasse DriverManager sucht dabei einen passenden Treiber aus der Liste der registrierten JDBC-Treiber für die Datenbank. |
|
static Connection getConnection( String url, String user, String password )
throws SQLException
Versucht eine Verbindung zur Datenbank aufzubauen. user und password werden für die Verbindung zur Datenbank verwendet. |
|
static Connection getConnection( String url, Properties info )
throws SQLException
Versucht eine Verbindung zur Datenbank aufzubauen. Im Properties-Objekt können die Felder »user« und »password« sowie weitere Informationen vorhanden sein. |
 Hier klicken, um das Bild zu Vergrößern
Wie der Treiber gefunden wird
Es lohnt sich, einmal hinter die Kulissen der Methode getConnection() zu blicken. Das DriverManager-Objekt wird veranlasst, die Verbindung zu öffnen. Dabei versucht es, einen passenden Treiber aus der Liste der JDBC-Treiber auszuwählen. Sein Treiber verwaltet die Klasse DriverManager in einem privaten Objekt DriverInfo. Dieses enthält ein Treiber-Objekt (Driver), ein Objekt (securityContext) und den Klassennamen (className).
Während getConnection() die Liste der DriverInfo-Objekte abgeht, versucht dieser, sich über die connect()-Methode anzumelden. Bemerkt der Treiber, dass er mit der URL nicht viel anfangen kann, gibt er null zurück, und getConnection() versucht es mit dem nächsten Treiber. Ging alles daneben, und keiner der angemeldeten Treiber konnte etwas mit dem Subprotokoll anfangen, bekommen wir eine SQLException("No suitable driver", "08001").
Verbindung beenden
Da eine Verbindung zu schließen ist (und nicht der DriverManager), finden wir eine Methode close() beim Connection-Objekt. Verbindungen zu schließen ist immens wichtig, sodass dieser Teil im Allgemeinen im finally-Block sitzt.
Connection con = null;
try {
con = ...
...
} finally {
con.close(); // Umgeben von if con!=null und zusätzlichem try/catch
}
interface java.sql. Connection
|
|
void close() throws SQLException
Schließt die Verbindung zur Datenbank. Auch hier kann eine SQLException auftauchen. |
Wartezeit einstellen
Wenn wir uns mit der Datenbank verbinden, lässt sich noch eine Wartezeit in Sekunden einstellen, die angibt, wie lange der Treiber für die Verbindung mit der Datenbank warten darf. Gesetzt wird dieser Wert mit setLoginTimeout() und entsprechend ausgelesen mit getLoginTimeout(). Standardmäßig ist dieser Wert 0.
class java.sql. DriverManager
|
|
static void setLoginTimeout( int seconds )
Setzt die Zeit, die maximal gewartet wird, wenn der Treiber sich mit einer Datenbank verbindet. |
|
static int getLoginTimeout()
Liefert die Wartezeit in Sekunden. |
1 Früher org.gjt.mm.mysql.driver
|