![]() |
|
Zur praktischen Anwendung der Kenntnisse, die in diesem Kapitel vermittelt wurden, werden nun die Grundlagen der JDBC-Datenbanktechnik anhand eines Beispiels betrachtet. Es sei darauf hingewiesen, dass dieses Beispiel das DBMS Access der Firma Microsoft verwendet. Um andere Datenbanken zu verwenden, muss lediglich der JDBC-ODBC-Treiber in der folgenden Zeile auf den gewünschten Treibertyp umgestellt werden.
Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver"); Das hier betrachtete Beispiel ist eine Java-Anwendung, die lokal auf dem Rechner eines Clients ausgeführt wird. Im Einzelnen werden die folgenden Aufgaben wahrgenommen:
Um das Beispiel fehlerfrei ausführen zu können, muss im ersten Schritt der JDBC-ODBC-Treiber für die Datenbank installiert werden. Das geschieht unter Windows, indem die folgenden Schritte durchgeführt werden:
Wie in allen weiteren Kapiteln dieses Buches auch wird der
import java.sql.*; // Klassendefinition static String query_str; // fuer die Abfrage // Anzahl gespielter Runden Zunächst werden die Komponenten des Packages java.sql importiert, zu denen die Klassen Connection, DriverManager, Statement, PreparedStatement, ResultSet, DataBaseMetaData und SQLException gehören, die im Laufe dieses Beispiels benötigt werden. Anschließend werden einige statische Variablen definiert, anhand derer Anfragen gesendet und Ergebnisse bearbeitet werden können.
public static void main(String args[]) { // Programminformationen ausgeben: System.out.println("--openjava----openjava----openja va----openjava----openjava----openjava--"); Die main-Methode wird ohne Argumente aufgerufen. Man könnte das Programm auch mit Argumenten aufrufen, um bspw. ein Passwort und eine Benutzeridentifikation zu übergeben. Zweck der oben dargestellten Zeilen ist es, Ausgabeinformationen anzuzeigen. Die formatierte Ausgabe der obigen Zeilen sieht bspw. wie folgt aus:
--openjava----openjava----openjava----openjava----openja va----openjava-- Programm: erzeugeTabelle Version: 1.0 --openjava----openjava----openjava----openjava----openja va----openjava-- Anschließend wird der Treiber geladen und eine Datenbank-URL spezifiziert, woraufhin die Verbindung zur Datenbank geöffnet werden kann. Bei der Herstellung dieser Verbindung werden weder Benutzername noch Passwort verwendet. Die dazu vorgesehenen Felder bleiben dementsprechend leer.
try { // Laden des JDBC-ODBC-Treibers // Datenbank-URL spezifizieren. Die Datenbank heisst hier // Eine Verbindung zur Datenbank herstellen // Weiterer Verlauf dieses Beispiels } // Benoetigtes Exception-Handling catch(SQLException sqlex) { System.out.println("ERROR: Datenbankfehler: " + sqlex.getMessage()); }
catch(Exception exp) { System.out.println("ERROR: Sonstiger Fehler: " + exp.getMessage()); Die formatierte Ausgabe besteht hier lediglich aus der folgenden Zeile.
INFO: Verbindung zur Datenbank erfolgreich hergestellt. Anschließend wird ein Statement erzeugt, das im weiteren Verlauf dazu verwendet wird, um die Tabelle zu löschen. Das Code-Fragment befindet sich innerhalb einer try-catch Anweisung, damit das Programm nicht abstürzt, wenn keine Tabelle, die gelöscht werden kann, vorhanden ist. Eine andere Möglichkeit wäre, abzufragen, ob eine Tabelle vorhanden ist oder nicht. Wie diese Abfrage formuliert werden muss, wird im Folgenden durch die Metadaten-Abfrage näher erläutert. Nachdem die Tabelle gelöscht wurde, wird eine neue Tabelle erzeugt, die aus vier Spalten besteht. Hiermit kann demonstriert werden, wie die im Laufe dieses Kapitels besprochene Tabelle „Spieler" mit Java erzeugt werden kann. Das Löschen bzw. das Erzeugen der Tabelle ist nicht zwingend notwendig und wurde nur vorgenommen, um die in diesem Kapitel erläuterte Theorie anhand eines praktischen Beispiels zu zeigen.
// Statements erzeugen // Loeschen der Spielertabelle, falls sie existiert mein_stmnt.execute("DROP TABLE Spieler" ); } catch (Exception e){ System.out.println(" Tabelle Spieler existiert nicht "); } // Neue Spielertabelle erzeugen System.out.println(" "); } Nachdem die Tabelle erfolgreich kreiert wurde, wird die folgende Zeile ausgegeben:
INFO: Tabelle erfolgreich erzeugt. Die Datensätze, die im theoretischen Teil erläutert wurden, werden in die derart erzeugte Tabelle eingefügt. Dafür wurde der SQL-Befehl INSERT INTO innerhalb der Methode executeUpdate des Objekts Statement verwendet. Um feststellen zu können, ob die Angaben tatsächlich in die Datenbank eingefügt wurden, wird in der Folge eine Anfrage an die Datenbank gestellt. Diese Anfrage ruft alle in der Tabelle vorhandenen Datensätze ab, die anschließend mit Hilfe der Methode SchreibeErgebnis angezeigt werden.
// Daten in die Tabelle Einfügen mein_stmnt.executeUpdate ("INSERT INTO Spieler " + " VALUES (1, 'ElSaddik', 'Abed', 4)" ); mein_stmnt.executeUpdate ("INSERT INTO Spieler " + " VALUES (2, 'Fischer', 'Stephan', 6)" ); mein_stmnt.executeUpdate ("INSERT INTO Spieler " + " VALUES (3, 'ElSaddik', 'Abutti', 8)" ); mein_stmnt.executeUpdate ("INSERT INTO Spieler " + " VALUES (4, 'Frankfurter', 'Richard', 2)" ); System.out.println(" "); // Nun wird eine Anfrage an die Datenbank gestellt, query_str = "SELECT Spieler_Nr, Nachname, Vorname, Gespielt FROM Spieler"; // Abfrage ausfuehren und Ergebnisse anschauen Das formatierte Ergebnis dieser Transaktionen sieht wie folgt aus:
INFO: Werte erfolgreich in die Tabelle eingegeben. openjava----openjava----Zeige Tabellen Inhalt----openjava----openjava-- Spieler_Nr: Name Vorname Gespielt 1 ElSaddik Abed 4 2 Fischer Stephan 6 3 ElSaddik Abutti 8 4 Frankfurter Richard 2 Anschließend wird das Objekt PreparedStatement verwendet, um die Anzahl der gespielten Runden für die Spieler mit Nachnamen „ElSaddik" auf 44 zu setzen. Hierbei wurde explizit nicht die Spielernummer ausgewählt, um darzulegen, dass eine derartige Änderung alle Datensätze betrifft, wenn nicht mit einem eindeutigen Schlüssel gearbeitet wird. Die Anweisung PreparedStatement erwartet zwei Variablen: Die Anzahl der gespielten Runden und den Nachnamen des Spielers. Diese werden durch das Verwenden der zwei setxxx-Methoden (setInt() und setString()) auf die entsprechenden Werte gesetzt. Jede dieser Methoden akzeptiert wiederum zwei Argumente. Das erste Argument repräsentiert die Ordinalposition der einzusetzenden Variablen, das zweite Argument den Wert dieser Variablen.
// Verwendung von PreparedStatement // Setzen der jeweiligen Variablen mit den entsprechenden // Tabelle Aktualisieren Um das Ergebnis dieser Aktualisierung ansehen zu können, wird eine neue Anfrage an die Datenbank gesendet, woraufhin als Resultat die Ergebnisse angezeigt werden. Das Argument der Methode executeQuery kann hierbei entweder direkt oder durch die Definition einer String-Variablen (query_str) angegeben werden:
// Neue Anfrage an Datenbank senden, // Abfrage ausfuehren und Ergebnisse anschauen Das formatierte Ergebnis ist im Folgenden angegeben. Hierbei erkennt man, dass die Datensätze beider Spieler mit dem Nachnamen „ElSaddik" aktualisiert worden sind.
-openjava----openjava----PreparedStatement Verwenden----openjava- Spieler_Nr: Name Vorname Gespielt 1 ElSaddik Abed 44 2 Fischer Stephan 6 3 ElSaddik Abutti 44 4 Frankfurter Richard 2
Abschließend wird nochmals die Verwendung der Anweisung PreparedStatement betrachtet. Diese Klasse wird nun dazu eingesetzt, um Datensätze aus der Datenbank zu löschen. Dies muss erfolgen, indem ein PreparedStatement-Objekt definiert und anschließend zur Ausführung an die Datenbank gesendet wird. Hierbei wird nur eine Variable übergeben, in diesem Fall der Nachname eines Spielers. Deswegen muss nur eine der setxxx-Methoden verwendet werden, hier die Methode setString():
// Benutzung von PreparedStatement, // Setzen der jeweiligen Variablen mit der entsprechenden // Tabelle aktualisieren // Senden einer neuen Anfrage an die Datenbank, // Abfrage ausfuehren und Ergebnisse darstellen Das Ergebnis dieses Löschvorgangs ist im Folgenden angegeben.
--openjava----openjava----PreparedStatement zum Löschen verwenden----openjava----openjava-- Spieler_Nr: Name Vorname Gespielt 2 Fischer Stephan 6 4 Frankfurter Richard 2 Bis zu dieser Stelle wurden das Erzeugen und das Löschen einer Tabelle bzw. verschiedene Manipulationsoperationen betrachtet. Im Folgenden wird das Beispiel um die Eigenschaft, JDBC-Metadaten der Datenbanken während der Laufzeit eines Java-Programms zu ermitteln, erweitert. JDBC-Metadaten Die Ermittlung von Metadaten einer Datenbank wird dadurch möglich, dass JDBC die Klasse DatabaseMetaData zur Verfügung stellt. Die Erzeugung einer Instanz dieser Klasse ähnelt der eines Connection-Objekts, das nicht mit Hilfe des Schlüsselwortes new erzeugt wird, sondern durch die Verwendung des bereits vorhandenen Connection-Objekts bzw. der Methode getMetaData().
// Erzeugen des Metadatenobjekts if (meine_metadata == null) { System.out.println ("Keine Datenbank-Metadaten vorhanden"); } else { // Ausgeben der Informationen ueber das RDBMS // Weitere Abfragen, um Metadateninformationen der } Die allgemeinen Metadaten der Datenbank dieses Beispieles sind im Folgenden angegeben. Wird eine andere Datenbank verwendet, so sehen die unten angegebenen Metadaten dementsprechend anders aus.
--openjava----openjava----Datenbank Information----openjava----openjava-- Datenbank Produktname: ACCESS Datenbankversion: 3.5 Jet JDBC-Treibername: JDBC-ODBC Bridge (ODBCJT32.DLL) Treiberversion: 1.2001 (03.50.3428.00) URL: jdbc:odbc:openjava Benutzer: admin Das folgende Code-Fragment wird benötigt, um den ANSI-Standard für die SQL-Version abzufragen, die durch die Datenbank unterstützt wird:
if(meine_metadata.supportsANSI92FullSQL()) { System.out.println("Ansi92 SQL: Voll unterstützt"); } else { if(meine_metadata.supportsANSI92IntermediateSQL( )) { System.out.println("Ansi92 SQL (1): Teilweise unterstützt"); } else { if(meine_metadata.supportsANSI92EntryLevelS QL()) { System.out.println("Ansi92 SQL: Ansatzweise unterstützt"); } else { System.out.println("Ansi92 SQL: wird nicht unterstützt"); } } } Das Ergebnis dieser Abfrage könnte wie im Folgenden dargestellt aussehen. Das Ergebnis kann aber von Benutzer zu Benutzer variieren, da es in großem Maße von der verwendeten Datenbank abhängig ist.
Ansi92 SQL: Ansatzweise unterstützt Diese Ausgabe bedeutet, dass nur SQL der Form ANSI92-EntryLevel unterstützt wird. Durch die Methode supportsStoredProcedures() wird festgestellt, ob die Datenbank gespeicherte Prozeduren unterstützen kann.
if(meine_metadata.supportsStoredProcedures()) { System.out.println("Stored Procedures: werden unterstützt"); } else { System.out.println("Stored Procedures: werden nicht unterstützt"); } Die Datenbank dieses Beispiels unterstützt gespeicherte Prozeduren, weshalb sich die folgende Ausgabe ergibt:
Stored Procedures: werden unterstützt Das JDBC-API beinhaltet eine Vielzahl von Methoden, um Metadaten einer Datenbank abzufragen. Im Folgenden sind die Transaktionsmöglichkeiten der Datenbank, die in diesem Beispiel verwendet wird, aufgelistet.
if(meine_metadata.supportsTransactions()) { System.out.println("Transaktionen: werden unterstützt"); } else { System.out.println("Transaktionen: werden nicht unterstützt"); } System.out.println("Multiple Transaktionen: werden unterstützt"); } else { System.out.println("Multiple Transaktionen: werden nicht unterstützt"); } System.out.println("Datendefinitions- und Datenmanipulationstransaktionen: werden unterstützt"); } else { System.out.println("Datendefinitions- und Datenmanipulationstransaktionen: werden nicht unterstützt"); } Das Ergebnis einer derartigen Abfrage könnte wie folgt aussehen:
Transaktionen: werden unterstützt Im Folgenden wird aufgezeigt, wie anhand der Metadaten sowohl der Name der Tabelle als auch deren Struktur ausgelesen werden kann. Die Tabellen werden hierbei mit Hilfe der Methode getTables() abgefragt.
// Ermittle die Tabellen sowie deren Aufbau // Liste aller Tabellen ermitteln // Tabellen-Information ausgeben String tabellen_name = meine_Tabellen_Ergebnisse.getString(3); // Anfrage stellen, um Tabellenspalten und } Da in der betrachteten Datenbank nur die Tabelle „Spieler" existiert, sieht das Ergebnis wie folgt aus:
Tabellenname: Spieler Anschließend wird eine Anfrage formuliert, um alle Spalten der Tabelle als Ergebnis zu erhalten.
ResultSet meine_Spalten_Ergebnisse = mein_stmnt.executeQuery("SELECT * FROM "+ tabellen_name); Nachdem durch die oben beschriebene Anfrage der Inhalt der Tabelle abgefragt wurde, wird die Anzahl der Spalten durch die Methode getColumnCount() ermittelt. Aus jeder Spalte können nun Informationen ausgelesen werden. Im folgenden Beispiel werden der Spaltenname, der Datentyp der Spalte und die Möglichkeit, Werte der Spalten zu überschreiben, abgefragt. Abschließend wird ermittelt, ob der Inhalt bezüglich der Groß- und Kleinschreibung unterschieden werden kann.
ResultSetMetaData rsmd = meine_Spalten_Ergebnisse.getMetaData(); int anzahlDerSpalten = rsmd.getColumnCount(); for (int i=1; i<=anzahlDerSpalten; i++){ String spaltenName = rsmd.getColumnName(i); } Die Ergebnisse dieser Anfragen sieht wie folgt aus:
Name der Spalte: Spieler_Nr Mittels der Metadaten kann auch der Inhalt einer Tabelle gelesen werden. Dies wird im folgenden Beispiel verdeutlicht:
while(meine_Spalten_Ergebnisse.next()) { System.out.println(" "); String derString = meine_Spalten_Ergebnisse.getString(i); } } In der abgefragten Tabelle existieren daher zwei Zeilen, wodurch folgendes Ergebnis erscheint:
2 Fischer Stephan 6 4 Frankfurter Richard 2 Abbau der Datenbankverbindung Nach Beendigung der Arbeit mit der Datenbank muss die Verbindung zur Datenbank abgebaut werden. Hierzu ist der folgende Code notwendig.
// Verbindung zur Datenbank beenden Hilfsroutinen Für das im Laufe dieses Teilkapitels betrachtete Beispiel wurden zwei Hilfsmethoden geschrieben, die Methoden FormatierteAusgabe und SchreibeErgebnis. Die Methode FormatierteAusgabe dient dazu, die Ausgabe in eine lesbare Form zu bringen. Ein als Parameter übergebener String wird daher mit Leerzeichen bis zu einer angegebenen Länge aufgefüllt. Die Methode FormatierteAusgabe wurde wie folgt realisiert:
private static String FormatierteAusgabe(String st, int i) { String leereZeile = " "; return st.concat(leereZeile.substring(0, ( i-st.length() ) )); else return st; } Die zweite Methode, SchreibeErgebnis, dient dazu, Texte auszugeben, die als Ausgabe der Methode FormatierteAusgabe() entstehen.
public static void SchreibeErgebnis(ResultSet rs) { //Abfrageergebnis bearbeiten und ausgeben try{ // Solange die Tabelle Daten enthaelt, spieler_nummer = new Integer(rs.getInt("Spieler_Nr")); spieler_name = rs.getString("Nachname"); } } catch(SQLException sqlex) { System.out.println("ERROR: Datenbankfehler: " + sqlex.getMessage()); } } |
|
|