Eine Einführung in das Java Paket JDBC Seminararbeit von Christian Harwalik Abteilung Anwendersoftware (AS) Institut für Parallele und Verteilte Systeme (IPVS) Universität Stuttgart Betreuer Uwe Heinkel Sommersemester 2002 Eine Einführung in das Java Paket JDBC Seite 2 Zusammenfassung In dieser Ausarbeitung werden die Hintergründe und der Aufbau von der Java Database Connectivity beschrieben, und die Funktionsweise erläutert und beurteilt. Außerdem wird zuvor noch kurz auf die anderen Möglichkeiten eingegangen, um auf Datenbanksysteme zuzugreifen. JDBC ist eine offene und standardisierte Schnittstelle für Java-Programme oder Applets zum Zugriff auf relationale Datenbank-Management-Systeme (RDBMS) fast aller Hersteller[6]. Es bietet die Möglichkeit, um mit Java auf relationale Datenbanken zugreifen zu können, SQL Anweisungen auszuführen und die Ergebnisse zu verarbeiten. JDBC ist sehr mächtig und hat, da es ein Java Paket ist, die Vorteile, die Java mit sich bringt. JDBC ist ein weit geltender Standard, und eine Myriade (Vielzahl) der JDBC Treiber stehen heute zum Download zur Verfügung[5]. Eine Einführung in das Java Paket JDBC Seite 3 Inhaltsverzeichnis Seite 1. Einführung 1.1 Zugriffe auf Datenbanksysteme 1.2 Was ist JDBC 1.3 ODBC 2. Die Architektur 2.1 Zweischichten Architektur (Direct-to-Database) 2.2 Dreischichten Architektur 3. Die verschiedenen Treiber-Arten 3.1 Typ-1 / JDBC-ODBC-Bridge & ODBC Driver 3.2 Typ-2 / Native API partly Java Driver 3.3 Typ-3 / JDBC Net pure Java Driver 3.4 Typ-4 / Native Protocol pure Java Driver 3.5 Vergleich der Treiber Typen 4. Die Grundstruktur eines JDBC Programms 4.1 Importieren der Klassen 4.2 Laden eines JDBC-Treibers 4.3 Herstellung der Verbindung zur Datenbank 4.4 Anfrage erstellen 4.5 Anfrage ausführen 4.5.1 Statement 4.5.2 PreparedStatement 4.5.3 CallableStatement 4.6 Ergebnisse abfragen 4.7 Metadaten 4.8 JDBC Fehlerbehandlung von SQL Exceptions 4.8.1 java.sql.SqlException 4.8.2 java.sql.SQLWarning 4.8.3 java.sql.DataTruncation 4.9 Mapping von SQL und Java Datentypen 5. Fazit 6. Quellenverzeichnis 4 4 5 5 6 6 7 8 8 9 10 10 11 11 12 12 13 13 13 13 14 15 16 16 16 16 17 17 18 18 19 Eine Einführung in das Java Paket JDBC Seite 4 1. Einführung Heutzutage haben Datenbanken und Anwendungen, die auf Datenbanken zugreifen, große Bedeutung erlangt und diese wird in Zukunft noch zunehmen. Dabei sind Datenbanken oft die einzige Möglichkeit, den Benutzern eine gemeinsame Datenbasis zur Verfügung zu stellen. Der Datenbanksystemanwender greift dabei nicht direkt auf die Daten zu, sondern nutzt spezielle Schnittstellen, über welche die Daten in zentralen Datenbankmanagementsystemen (DBMS) abgefragt, geändert, eingefügt oder gelöscht. Hierbei stellen diese Aktionen auf den Daten in einem Datenbanksystem ein Problem dar, insbesondere im Hinblick auf die verschiedenen Schnittstellen der unterschiedlichen Anbieter von Datenbanksystemen. Gerade diese unterschiedlichen Schnittstellen führen zu Problemen auf Seiten der Client-Programme, wenn das DBMS gewechselt wird oder die Client-Anwendung auf ein DBMS eines anderen Herstellers zugreift. Um die Abfragen und Verwaltung von relationalen und objektrelationalen Datenbanksysteme zu vereinheitlichen, wurde SQL (structured query language) entwickelt. Allerdings handelt es sich hierbei nicht um eine funktional vollständige Programmiersprache. Deshalb können Anwendungen nicht direkt in SQL programmiert werden. Man benötigt also eine Sprache, in welche die SQLStatements „eingebettet“ werden können. 1.1 Zugriffe auf Datenbanksysteme Da wäre als erstes embedded SQL. Dies ist eine Erweiterung einer „Wirtssprache“ um SQL-Anweisungen. Hier werden SQL-Anweisungen in „Klartext“ in die Programmiersprachen eingebaut. Um die SQL-Anweisungen zu Kennzeichnen, wird bei den meisten Wirtssprachen (wie z. B. C/ C++) ein EXEC SQL am Anfang vor die Anweisung gestellt. Dieser Ansatz erfordert es, die SQL-Quelle durch einen Precompiler zu schicken, der den Source-Code erzeugt, den der Sprachcompiler versteht. Die gekennzeichnete Anweisung wird vom Precompiler verarbeitet und der Rest des Source-Codes wird unberücksichtigt durchgereicht. Die Nachteile hierbei sind: - für jeden Server der verschiedenen Hersteller der Datenbanken muss neu kompiliert werden; die prozedurale „Wirtssprache“ muss mit nicht prozeduralem SQL kombiniert werden. Eine weitere Möglichkeit ist SQLJ (ehemals JSQL), auch eine Form des embedded SQL mit der Wirtssprache Java. Die eingebetteten SQL-Anweisungen werden durch den Präprozessor, den SQLJ-Translator, aufbereitet. Der Präprozessor führt vor dem eigentlichen Kompilieren des Java-Codes eine Syntax-, Datentyp- und Schemaüberprüfung durch[10]. Aus den SQLJ-Quelltexten werden Java-Quelltexte generiert und das Ergebnis, nach dem kompilieren, ist eine Java-Datei, die mit dem Java-Compiler zu übersetzen ist. Eine Einführung in das Java Paket JDBC Seite 5 Eine weitere Möglichkeit ist Java Data Objects (JDO). Es definiert die Semantik, mit welcher eine Java-Anwendung ihre Datenobjekte in einer Datenbank abfragen und einfügen kann. JDO hilft dabei, auf Informationen in einem Datenspeicher (wie z. B. relationale oder objekt-orientierte Datenbanken) zuzugreifen, wobei diese Informationen als Java-Objekte erscheinen, so dass die Daten durch die direkte Nutzung von Java manipuliert werden können. 1.2 Was ist JDBC Durch Java Database Connectivity (JDBC), der Firma Sun Microsystems, gibt es noch eine weitere Möglichkeit, außer JDO, SQLJ usw., um auf Datenbanksysteme zuzugreifen. JDBC stellt eine Schnittstelle zur Verfügung, mit deren Unterstützung SQL-Datenbankanfragen gestellt und ausgewertet werden können. Im allgemeinen erfüllt JDBC drei Aufgaben: Es eröffnet eine Verbindung zu einer Datenbank, stellt eine SQL-Anfrage und bearbeitet die Ergebnisse. Bei JDBC ist das Datenbankverwaltungssystem unerheblich, im Bezug auf den Hersteller beziehungsweise den Anbieter dieses Datenbankverwaltungssystems. Dies bedeutet für JDBC, dass es Treiber für eine Vielzahl von Datenbanksystemen zur Verfügung stellt, gerade im Bezug auf die verschiedenen Datenbankverwaltungssysteme. Für die wenigen, für die es keinen JDBC spezifischen Treiber gibt, wird die ODBCSchnittstelle in JDBC angeboten. Einen ODBC Treiber stellt eigentlich jeder Hersteller von Datenbankmanagementsystemen zur Verfügung. Somit kann JDBC, über diese ODBC-Schnittstelle, auch für Datenbanken verwendet werden, für welche es nicht direkt in JDBC einen Treiber gibt. Die Anweisung kommuniziert mit der JDBC-Schnittstelle, und diese dann mit dem Datenbanksystem (z.B.: Oracle, DB2, Sybase, usw.). Es bietet die Möglichkeit, für den Entwickler von Anwendungen, eine Datenbankanwendung hauptsächlich in Java zu schreiben, d.h. man benötigt nur eine Programmiersprache und geringe Kenntnisse über SQL, oder man hat eine genaue Spezifikation der SQL-Statements, die ausgeführt werden. Da diese Schnittstelle komplett in Java implementiert ist, kann sie einfach in JavaApplikationen eingebunden werden und hat damit auch alle sonstigen Vorteile Javas, wie zum Beispiel die Plattformunabhängigkeit, zumindest wenn man nicht auf eine nativen Treiber (wird später noch behandelt) zurückgreifen muss, oder Verwendung in Verbindung mit Netzwerken, wie dem World Wide Web. Die Vorteile lassen sich kurz zusammenfassen. - Client/Server-Architektur, eingebaute Netzwerkfähigkeit nutzbar für fast jedes relationale DBMS voller Zugriff auf die Metadaten einer DB (was später noch erläutert wird) der Datenbankzugriff wird über eine URL identifiziert und ist damit eindeutig und leicht verständlich (was später noch erläutert wird). Eine Einführung in das Java Paket JDBC Seite 6 1.3 ODBC Open Database Connectivity (ODBC) ist eine Schnittstelle, welche von Microsoft entwickelt wurde[7]. Diese Schnittstelle stellt ebenfalls einige der oben erwähnten Möglichkeiten, auf Datenbanken zugreifen zu können, zur Verfügung. Die Unterstützung von ODBC ist nicht auf Microsoft beschränkt. DBMS-Hersteller wie Oracle, Informix, Novell, IBM, usw. unterstützen ODBC. SQL-Befehle werden bei ODBC zur Kommunikation mit dem Datenbanksystem eingesetzt. Diese werden in ODBC-Anweisungen eingepackt. Es findet keine Syntaxkontrolle statt, da ODBC die SQL-Befehle nicht interpretiert. Die SQL-Befehle werden an einen Treiber geschickt, welcher vom Hersteller der Datenbank zur Verfügung gestellt wird. Der Treiber sendet die Befehle an die Datenbank, nimmt die Antworten entgegen und übergibt sie an das ODBC-Programm. 2. Die Architektur Es existieren zwei unterschiedliche Architekturen um mittels JDBC eine Verbindung zwischen einer Applikation und einer Datenbank aufzubauen. Welche eingesetzt wird, ist von den Anforderungen der Anwendung bzw. der Hardware- und Software-Umgebung des Einsatzgebietes von JDBC abhängig. Außerdem ist die Art des zur Verfügung stehenden Treibers bei der Entscheidung maßgeblich, was später noch behandelt wird. 2.1 Zweischichten Architektur (Direct-to-Database) In der „Two-Tier-Architecture“ (Abb. 1) wird durch eine Applikation eine Verbindung zur Datenbank durch einen Datenbanktreiber aufgebaut. Dieser Treiber ist dann für den Datenaustausch mit der Datenbank verantwortlich ist. Die Applikation ist somit zuständig für die Funktionalität des Datenaustausches. Abb. 1 Two-Tier Architektur [13] Diese Architektur entspricht der klassischen Client-Server-Architektur. Ein typisches Beispiel ist das Laden eines Java-Applets mit Hilfe eines Browsers auf dem Client, Eine Einführung in das Java Paket JDBC Seite 7 welches vom Server geladen wird. Dieses Applet kommuniziert direkt mit dem Datenbankserver und kann, aufgrund der strengen Sicherheitsvorschriften für Applets, nur mit dem Rechner in Verbindung treten, von welchem das Applet geladen wurde. Dies bedeutet, dass Web-Server und die Datenbank auf dem selben Rechner zur Verfügung stehen müssen. Es existieren zwei Arten des Zweischichten Modells: 1. Ein Java-Applet, auf einem Client System, wird von einem Server geladen und verbindet sich über ein DBMS-spezifisches Protokoll mit der Datenbank. 2. Ein Java-Applet wird vom Server auf das Client System geladen und verbindet sich über einen nativen DBMS-Treiber mit der Datenbank, welche ebenfalls auf dem gleichen Rechner liegen muss wie der WebServer mit dem sich das Applet verbindet. Auf diese beiden Modelle wird bei den Treibertypen genauer eingegangen. Zu diesem Zweischichten-Modell gibt es noch einige weitere Dinge anzumerken. Erstens wird eine leistungsfähige Maschine vorausgesetzt um einen Web-Server und einen Datenbankserver auf ein und demselben Rechner laufen zu lassen. Außerdem ist die Sicherheit der Datenbank geringer als bei dem Dreischichten Modell, da der Client direkt an den Rechner kommt, auf dem der Datenbankserver ist. Des weiteren muss der „pure java-„-Treiber bei jeder Verbindung zu dieser Datenbank erneut vom Web-Server geladen werden, was die Ladezeit des Applets verlängert, vereinfacht dafür aber die Softwareverteilung und Portabilität. Im Gegensatz dazu ist das Laden des nativen Treibers vom lokalen Rechner bedeutend schneller, aber es setzt ein Applet voraus und erschwert die Softwareverteilung und schränkt die Portabilität ein. Wenn eine Datenquelle nun verteilt vorliegt, also erstens der Web-Server und der DB-Server auf verschiedenen Maschinen liegen oder die Daten auf verschiedenen DB-Servern liegen, so muss entweder der JDBC–Treiber über Netzwerkfähigkeiten verfügen oder man benutzt das Dreischichten Modell. 2.2 Dreischichten Architektur Bei der sogenannten „Three-Tier-Architecture“, Abb. 2, liegen der Web-Server und der Datenbankserver auf getrennten Rechnern, bzw. können die Daten auch auf verschiedenen Datenbankservern zur Verfügung stehen. Dieses Modell benötigt einen „middle-tier Server“, welcher als Gateway zu den Datenbankservern dient. Am Beispiel eines Applets, wird bei dieser Architektur ein Applet vom Web-Server geladen, welches sich über ein Protokoll, welches von dem Datenbanksystem unabhängig ist, mit einem Gateway auf dem Web-Server verbindet und dann als Datenbank-Client die Abfragen für das Applet übernimmt. Die Ergebnisse der Datenbank werden anschließend an das Applet zurückgesendet. Ein Beispiel für dieses Modell ist eine Verbindung zweier Java-Applets mit Hilfe von Remote Method Invocation. RMI ermöglicht Java mit verteilten Systemen zu kommunizieren. Eine Einführung in das Java Paket JDBC Seite 8 Es stellt Java-Klassen und entsprechende Methoden bereit, um vom Client-Applet aus mit Serverobjekten Daten auszutauschen. Abb. 2 Three-Tier Architektur [13] Hierzu sollte man anmerken, dass die Trennung von Web-Server und Datenbankserver die Maschinen auf denen diese Server laufen entlasten. Weiterhin erhöht es die Sicherheit bei Zugriffen auf DB-Server, da der Zugriff nur über ein Gateway möglich ist, auf dem zum Beispiel Java Applikationen und JDBC Treiber sind um mit der/den Datenbank/en zu kommunizieren (wie in Abbildung 2 ersichtlich ist). Allerdings ist dafür die Programmierung des Gateways erheblich komplexer, da eine Umsetzung der unabhängigen Datenbanksystem-anweisungen in spezifische Datenbanksystembefehle benötigt wird. 3. Die verschiedenen Treiber-Arten Die Anwendung von JDBC verlangt den Einsatz von Treibern für die verwendete Datenbank, welche über den sogenannten JDBC-Treiber-Manager verwaltet bzw. geladen werden. Diese Treiber lassen sich in vier verschiedene Kategorien unterteilen. Die Unterschiede in den Architekturen der einzelnen Treiber werden nachfolgend erläutert. Eine Einführung in das Java Paket JDBC Seite 9 3.1 Typ-1 / JDBC-ODBC-Bridge & ODBC Driver: Bei dieser Variante wird der Typ 1 Treiber (JDBC-ODBC-Bridge) benützt, um über eine ODBC-Schnittstelle mit der Datenbank zu kommunizieren. Ein solcher Treiber wird in JDBC angeboten. Allerdings muss auf allen Clients eine ODBC-Schnittstelle installiert sein (Abb. 3). Die grau-schattierten Boxen sind der Java bzw. der JDBC Teil dieser Architektur. Abb. 3 JDBC-ODBC-Bridge und ODBC Driver [1] 3.2 Typ-2 / Native API partly Java Driver: Bei dieser Architektur wird der native ODBC-Treiber durch einen nativen herstellerabhängigen Treiber (z.B. einen Oracle-Treiber) ersetzt. Er ist zur Anwendung hin in Java und zur Datenbank hin nativ programmiert. Dieser Treiber ist plattformabhängig und muss, zur Anwendung hin, bei jedem Client installiert werden (Abb. 4). Auch hier sind die grau-schattierten Boxen der Teil, welcher durch JDBC/Java zur Verfügung gestellt wird. Eine Einführung in das Java Paket JDBC Seite 10 Abb. 4 Native API partly Java Driver [1] 3.3 Typ-3 / JDBC Net pure Java Driver : Abb. 5 JDBC Net pure Java Driver [1] Bei diesem Treiber-Typ (Abb. 5) erspart man dem Client die lokale Installation eines Treibers durch den Einsatz einer serverseitigen Middleware-Installation, welche den Eine Einführung in das Java Paket JDBC Seite 11 Datenbankzugriff realisiert. Die Middleware beziehungsweise das Gateway dient als Verteilungsplattform. Sie macht die Kommunikation zwischen allen möglichen JavaClients und den unterschiedlichsten Datenbankmanagementsystemen möglich. Der universelle Treiber kann vom Server, durch JDBC (hier grau-schattiert) geladen werden. 3.4 Typ-4 / Native Protocol pure Java Driver: Bei dieser Variante werden Treiber verwendet, welche in purem Java-Code programmiert sind, um eine Anbindung von nativem Code zu vermeiden. Diese Alternative bietet, durch die fehlende Einbindung von nativem Code, auf der einen Seite die Unterstützung der Plattformunabhängigkeit von Java und andererseits dem Client die Möglichkeit den Treiber vom Webserver zu laden (Abb. 6). Abb. 6 Native Protocol pure Java Driver [1] 3.5 Vergleich der Treiber Typen Zu beachten ist, dass die Typen 1 und 3 keine Netzwerkfähigkeiten zur Verfügung stellen um direkt auf ein DBMS zuzugreifen. Sie können also nur mit Hilfe JDBC fremder Komponenten, wie ODBC Treiber, in Applets verwendet werden. Im Gegensatz dazu verwenden die Typen 2 und 4 ein Netzwerkprotokoll, wodurch entfernte Datenbanken angesprochen werden können. Leider sind diese Treibertypen nicht für alle Datenbanken verfügbar, so dass dann auf den Typ 1 oder 3 zurückgegriffen wird. Die Typen 3 und 4 bieten allerdings alle Vorteile von Java, da sie komplett in Java geschrieben sind. 4. Die Grundstruktur eines JDBC Programms Jede JDBC Anwendung kann zuerst einmal grob in drei Bereiche unterteilt werden. Zuerst wird eine Verbindung zur Datenbank hergestellt. Danach werden SQL Eine Einführung in das Java Paket JDBC Seite 12 Anfragen formuliert. Darauf können dann die Ergebnisse bearbeitet werden, wie in Abbildung 7 ersichtlich ist. Abb. 7 Elemente einer JDBC Anwendung Wenn man sich die Schritte genauer ansieht lässt sich eine feinere Einteilung vornehmen: - Importieren der notwendigen Java-Klassen und Interfaces Laden eines JDBC-Treibers Herstellung einer Verbindung zur Datenbank Erstellen der Statements Ausführen der Statements Abfragen der Ergebnisse Beenden der Verbindung zur Datenbank Diese Schritte liefern jeweils ein Objekt aus einer JDBC-Klasse/Schnittstelle, die Methoden für den folgenden Schritt bereitstellen (java.sql.DriverManager, java.sql.Connection, java.sql.Statement, java.sql.ResultSet). Die einzelnen Schritte werden im Folgenden weiter ausgeführt. 4.1 Importieren der Klassen Das Paket java.sql stellt alle notwendigen Klassen und Interfaces zur Ausführung von JDBC zur Verfügung. Die Klassen müssen am Beginn des Java-Programms importiert werden. Für JDBC wäre dies: import java.sql.*; Der * sorgt dafür, dass alle Klassen in diesem Paket importiert werde. 4.2 Laden eines JDBC-Treibers Zur Ausführung der JDBC-Anweisungen muss ein Datenbanktreiber geladen werden, der diese Anweisungen in eine Sprache (Code) umwandelt, die von dem jeweiligen Datenbanksystem verstanden wird. Zum Beispiel die JDBC-ODBC-Bridge, die in Verbindung mit einem lokal installierten und eingerichteten ODBC-Treiber jede Datenbank, die einen ODBC-Treiber zur Verfügung stellt, ansprechen kann, oder ein nativer Treiber für eine spezielle Datenbank (z. B. der Oracle-JDBC-Treiber). Im Normalfall übernimmt der DriverManager, auf den später noch eingegangen wird, die Auswahl des Treibers. Eine Einführung in das Java Paket JDBC Seite 13 4.3 JDBC URLs Durch den Aufruf der Methode DriverManager.getConnection erhält man ein Objekt der Klasse Connection. Dies repräsentiert eine Verbindung. Diese Methode erwartet als Argument eine URL der Struktur jdbc:<Unterprotokoll>:<Untername>. Ein Beispiel hierfür ist (User und Passwort sind optional): Connectin con = DriverManager.getConnection(“jdbc:odbc:Test”, User, Pw); 4.4 Herstellung der Verbindung zur Datenbank Sobald die DriverManager Klasse geladen und registriert ist, besteht die Möglichkeit eine Verbindung zur Datenbank herzustellen. Wenn nun eine Verbindung mit Hilfe der Methode Drivermanager.getConnection gestartet wird, prüft der DriverManager jeden Treiber der Reihe nach, und verwendet den ersten passenden. Hierbei kann es auch vorkommen, dass es mehrere passende Treiber gibt. Die Reihenfolge, welcher Treiber nach einem anderen kommt, wird in der Reihenfolge festgelegt, in der die Treiber registriert wurden (die Treiber in jdbc.drivers werden immer zuerst registriert). Hier ein Beispielcode für eine Verbindung mit einem JDBCODBC-Bridge-Treiber: Class.forName("jdbc.odbc.JdbcOdbcDriver"); //loads the driver String url = "jdbc:odbc:fred"; Connection con = DriverManager.getConnection( url, "userID", "passwd"); Die Variable „con“ stellt einen Anschluss zur Datenquelle „fred“ dar, welche verwendet werden kann um SQL Anweisungen zu erstellen und auszuführen. 4.5 Anfragen erstellen Es bestehen drei Möglichkeiten um eine SQL-Anweisung an die verbundene Datenbank zu senden. Eine Anfrage kann mit den Interface Statement ( für einfache Anfragen), PreparedStatement (für IN-Parameter, wird precompiliert und für spätere Verwendung gespeichert) oder CallableStatement (um Stored Procedures auszuführen, zusätzlich OUT- und INOUT-Parameter) gestellt werden. Wenn eine Verbindung zu einer Datenbank besteht, so können die Methoden createStatement, prepareStatement oder prepareCall aus dem Objekt Connection aufgerufen werden. 4.5.1 Statement Eine Anweisung kann nur formuliert werden, wenn eine Instanz des Interface Statements erzeugt wurde. Ein Beispiel um eine Instanz einer Verbindung (con) auf die Instanz eines Statements (stmt) zu erzeugen wäre: Connection con = DriverManager.getConnection(url, "sunny", ""); Statement stmt = con.createStatement(); Eine Einführung in das Java Paket JDBC Seite 14 Die Anfragen können durch die Methoden executeQuery, executeUpdate oder execute gestellt werden. Die Methode executeQuery liefert als Resultat eine Liste wie zum Beispiel der SQL-Aufruf „SELECT“. ResultSet rs = stmt.executeQuery("SELECT Name, Berufsbezeichnung, Gehalt FROM Mitarbeiter"); Diese Anweisung liefert in der Variablen „rs“ eine scrollbare Liste mit den Ergebnissen des SQL Statements zurück. Die Methode executeUpdate wird benötigt um Veränderungen an Tabellen durchzuführen. Mit dieser Methode können die SQL-Anfragen INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE und ALTER TABLE formuliert werden. Die Rückgabewerte bei den Methoden INSERT, UPDATE und DELETE sind Zahlen, der veränderten, eingefügten oder gelöschten Zeilen. Bei CREATE TABLE, DROP TABLE und ALTER TABLE ist der Rückgabewert immer 0. stmt.executeUpdate ("DROP TABLE TB1"); Die Methode execute wird verwendet wenn mehrere ResultSets zurückgeliefert werden. Dabei können diese Listen oder Updatewerte enthalten. Diese Methode kann dann verwendet werden, wenn es möglich ist, dass eine Anweisung mehr als nur ein Resultat zurückgibt, mehr als nur einen Rückgabewert (Zahlenwert) liefert oder eine Kombination von Resultat und Rückgabewert darstellt. Dies kann zum Beispiel zustande kommen, wenn man in der Datenbank gespeicherte Prozeduren ausführt. Im Normalfall kennt man allerdings die Rückgabewerte einer gespeicherten Prozedur, wenn man sie aufruft. 4.5.2 PreparedStatement Dieses Interface erbt vom Interface Statement. Es unterscheidet sich vom Statement auf zwei Arten. Erstens enthalten die Instanzen von PreparedStatement SQLAnweisungen, die bereits kompiliert worden sind. Ein Beispiel für ein PreparedStatements ist: Wenn eine Anfrage die Daten über eine Person liefern soll, diese anhand ihres Namens ermittelt wird und wenn diese Anfrage nun für verschiedene Personen (Müller, Maier, Schmitt, usw.) wiederholt werden soll wird hierfür ein PreparedStatement benutzt. Zweitens kann eine SQL-Anweisung im PreparedStatement ein oder mehrere IN-Parameter enthalten. Ein IN-Parameter ist eine Art Variable, deren Inhalt beim Erstellen der Anweisung noch nicht spezifiziert war. Diese Möglichkeit, IN-Parameter in ein Statement einzugeben, ist der Grund warum dieses Statement „prepared“ heißt. Ein „?“ dient als alias bzw. Platzhalter für die IN-Parameter, und diesem können zur Laufzeit verschiedene Werte zugewiesen werden. PreparedStatement pstmt = con.prepareStatement( "UPDATE Mitarbeiter SET Gehalt = ? WHERE Name = ?"); Dies ist die Vorbereitung einer Anfrage, bei der die Werte für die Variablen „Gehalt“ und „Name“ während der Laufzeit des Programms (z.B. einer Java Applikation) Eine Einführung in das Java Paket JDBC Seite 15 gesetzt werden können. Die Werte werden mit den Methoden setByte, setShort, setString, setLong, usw. gesetzt. Dies macht es möglich eine SQL-Anfrage mit verschiedenen Parametern zu stellen, ohne jedes Mal eine Instanz des Interfaces Statement zu erstellen. PreparedStatement.setLong(1, 4550); PreparedStatement.setString(2, Maier); Das erste Argument des „con.prepareStatement“ hat die Ordinalposition 1. Es dient der Zuordnung des ersten Parameters sowie des zugehörigen Wertes. In diesem Fall bewirkt die setLong Methode, dass die Variable „Gehalt“ auf „4550“ und „Name“ auf „Maier“ gesetzt wird. Diese Statements beziehungsweise Anfragen werden dann mit der entsprechenden executeQuery, executeUpdate und execute Methode gestellt. PreparedStatement.executeUpdate(); Nun müssen nur noch die Parameter gesetzt werden, bevor man die Anfrage senden kann. Dazu dienen die Methoden setxxx. Dabei sollte man aber auf die entsprechende Konvertierung achten. 4.5.3 CallableStatement Diese Methode bietet die Möglichkeit „stored procedures“, in der Datenbank gespeicherte Prozeduren, auszuführen. Ein CallableStatement-Objekt enthält den Aufruf einer gespeicherten Prozedur. Ein Beispiel hierfür wäre: procedure1 = Connection.prepareCall("{call getTestData(?, ?)}"); Als Erweiterung zu PreparedStatement können die Parameter nicht nur Eingabewerte sondern auch Ausgabewerte darstellen. Die Ergebnisse werden dann mit Methoden der Form getxxx ermittelt. Auf die Behandlung der Ergebnisse wird später noch genauer eingegangen. Dazu müssen die Fragezeichen, welche die Ausgabewerte enthalten werden, entsprechend initialisiert werden. Dabei wird der Typ des Rückgabewertes angegeben. CallableStatement cstmt = con.prepareCall( "{call getTestData(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.BIT); ResultSet rs = cstmt.executeQuery(); // . . . retrieve result set values with rs.getXXX methods byte x = cstmt.getByte(1); java.math.BigDecimal n = cstmt.getBigDecimal(2); Noch ein Hinweis zur Zuordnung der Platzhalter (Fragezeichen) und dem zugewiesenen Inhalt, in obigem Beispiel verweist die 1 in der Methode registerOutParameter auf das vordere Fragezeichen und die 2 in der Zeile darunter auf das hintere Fragezeichen. Eine Einführung in das Java Paket JDBC Seite 16 4.6 Ergebnisse Abfragen Der Rückgabewert bzw. das ResultSet, ist ein Objekt, welches die Ergebnisse einer SQL-Anfrage enthält. Diese Daten können über die Methoden next, deleteRow, findColumn, getArray, getString, usw. bearbeitet und spezielle Ergebnisse selektiert werden. Je nach Ergebnistyp (Sting, Array, Integer usw.) muss die entsprechende Methode aufgerufen werden. Die Methode ResultSet.next macht die erste bzw. die nächste Reihe im ResultSet verfügbar und gibt false zurück, wenn keine Daten mehr zur Verfügung stehen. Die allgemeine Form eines ResultSet entspricht einer Tabelle mit Spaltenbezeichnung und den zugehörigen Werten. 4.7 Metadaten Das Interface DatabaseMetaData liefert Informationen zu den Fähigkeiten/ Metadaten des Datenbanksystems und des JDBC-Treibers. Dies ist von großem Vorteil für die Entwicklung von Datenbankwerkzeugen und auch allgemein für die Entwicklungsumgebung. Das Interface wird erzeugt mit: DatabaseMetaData Metadaten = con.getMetaData(); Die Methode getMetaData wird auf die Instanz der Verbindung angewandt und über dieses DatabaseMetaData-Objekt lassen sich Informationen über die Datenbank abfragen(z. B. Produktname der Datenbank und dazugehörende Version, JDBCTreibername, die maximale Anzahl gleichzeitig geöffneter Statements, usw.). Das Interface ResultSetMetaData stellt Informationen über die Datentypen und Eigenschaften der Spalten in einem ResultSet zur Verfügung. Ein Beispiel zum erzeugen eines ResultSetMetaData-Objekt ist: ResultSet rs = stmt.executeQuery(“SELECT Name, Alter, Gehalt FROM Mitarbeiter”); ResultSetMetaData rsmd = rs.getMetaData(); ResultSetMetaData ist bei der Methode execute besonders nützlich, da hier die Anzahl und Art der Ergebnisse zur Übersetzungszeit unbekannt sind. 4.8 JDBC Fehlerbehandlung von SQL Exceptions Jede Methode der JDBC Klassen und Interfaces, bis auf die 5 Hilfsklassen (Date, DriverPropertyInfo, Time, Timestamp, Types) kann eine SQL Exception verursachen und ausgeben. Das macht die Fehlerbehandlung zu einem wichtigen Teil jeder Anwendung. 4.8.1 java.sql.SQLException (erweitert java.lang.Exception) Dies ist die Basisklasse aller anderen JDBC-Exceptions. Sie wird von Datenbankzugriffsfehlern oder anderen Fehlern ausgelöst. Um mehrere Fehler behandeln zu Eine Einführung in das Java Paket JDBC Seite 17 können werden in ihr die Fehler verkettet. Die wichtigsten Methoden dieser Klasse sind: - String getMessage (): Diese Methode liefert die Fehlerbeschreibung der Exception int getErrorCode(): Hier erhält man den „exception code“ für die ausgelöste SQLException String getSQLState(): Dies gibt eine Fehlermeldung nach der XOPEN SQLstate Konvention an SQLException getNextException(): Hier wird die nächste verkettete Fehlermeldung oder null zurückgegeben Es ist bei SQLExceptions nicht zwangsläufig notwendig, dass beim Auslösen einer solchen Exception die verursachende Methode nicht ausgeführt wird. Also ist es am sichersten nach einer Exception die Methode rollback zu nutzen um von vorne zu beginnen. 4.8.2 java.sql.SQLWarning (erweitert java.sql.SQLException) Diese Klasse stellt Informationen über Warnungen beim Zugriff auf eine Datenbank zur Verfügung. Nach dem Aufruf der Methode getWarnings wird die erste Warnung bereitgestellt. Existieren mehrere Warnungen, kann man mit der Methode getNextWarning die nächste Warnung abrufen. Bei den SQLWarnings ist zu beachten, dass bei Ausführung einer neuen Anweisung die Warnung einer vorangegangenen Anweisung entfernt wird. Die Informationen(z. B. ErrorCode), die beim Auftreten einer Warnung zur Verfügung gestellt werden, sind dieselben wie bei den SQLExceptions. Die wichtigsten Methoden sind hier: - SQLWarning getNextWarning(): Diese Methode gibt die nächste verkettete Warnmeldung zurück ansonsten existieren hier die gleichen Methoden wie bei SQLExceptions 4.8.3 java.sql.DataTruncation (erweitert java.sql.SQLWarning) Diese Klasse erbt von SQLWarning. Sie stellt Informationen zur Verfügung wenn von JDBC unerwartet Datenwerte abgeschnitten werden. Es kann unter bestimmten Umständen passieren, dass nur ein Teil eines Datenfeldes in eine Datenbank geschrieben oder aus ihr gelesen wird. Geschieht das „Kürzen“ (engl. truncation) beim Lesen aus einer Datenbank wird eine SQLWarning ausgegeben, beim Schreiben wird allerdings eine SQLException ausgelöst. Hier sollte beachtet werden, dass mehr Daten gesendet werden als der Treiber oder die Datenbank aufnehmen können, wenn während des Schreibens Daten gekürzt werden. In diesem Fall sollte ein DataTruncation-Objekt als eine SQLException ausgelöst werden. 4.9 Mapping von SQL und Java Datentypen Beim arbeiten mit Datenbanken ist das Mapping oder auch Abbilden der Datentypen ein sehr wichtiger Punkt. Der Grund ist, es gibt bei SQL andere Datentypen als bei Eine Einführung in das Java Paket JDBC Seite 18 Java. Daher muss dafür gesorgt werden, dass die Daten korrekt abgebildet werden. Allerdings bedeutet dies nicht, dass die Abbildung von Java und SQL Datentypen isomorph sein muss. Zum Beispiel der Java Datentyp String, der nicht vollständig auf SQL Datentyp CHAR abgebildet werden kann. Um diese unterschiedlichen Datentypen aufeinander abbilden zu können, definiert JDBC eine Menge generischer SQL-Typen in der Klasse java.sql.Types. Die Umsetzung erledigt im allgemeinen der Treiber. Abbildung von SQL auf Java Datentypen und von Java auf SQL Datentypen Abb. 8 Mapping Tabelle 5. Fazit Das Paket JDBC eignet sich als Schnittstelle zwischen Java und relationalen Datenbanken beziehungsweise Datenbankmanagementsysteme sehr gut. Dank des Treiber-Konzepts kann sich der Anwendungsentwickler auf die Entwicklung seiner Anwendung konzentrieren und muss kaum Zeit für die Anbindung verschiedener DBMS aufwenden. Mit Hilfe von JDBC lassen sich sehr komplexe und aufwendige Aufgaben und Probleme umsetzen beziehungsweise lösen . Eine Einführung in das Java Paket JDBC Seite 19 6. Quellenverzeichnis [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] J. Melton, A. Eisenberg: Understanding SQL and Java Together. Morgan Kaufmann, 2000. A.Kemper, A.Eickler: Datenbanksysteme – Eine Einführung; 4.Auflage; Oldenbourg Verlag München Wien; 2001 Getting Started with the JDBC API von Sun Microsystems Inc. http://java.sun.com/j2se/1.4/docs/guide/jdbc/getstart/GettingStartedTOC.fm.ht ml Sybase jConnect for JDBC Technical Whitepaper von Sybase http://www.sybase.com/detail/1,6904,1009766,00.html#top Developer’s Guide to Building XML-based Web Services with J2EE[tm] von James Kao Juni 2001 http://www.theserverside.com/resources/pdf/J2EEWebServices-DevGuide.pdf Enterprise Application Integration – Standardisierte Integration zur Bewältigung der IT-Herausforderungen von morgen von KPNG Consulting AG http://www.kpmg.de/services/consulting/ebusiness/docs/KPMG_EAI_Whitepap er_deutsch2002.pdf Whitepaper zum Einsatz der HOB-Produkte HOBLink DRDA, HOBDB online und HOB Database Gateway Extension von HOB http://www.hob.de/produkte/connect/drda_wpd.htm Gunter Saake und Kai-Uwe Sattler: Datenbanken & Java: JDBC, SQLJ und ODMG; 1. Auflage; Heidelberg: dpunkt-Verlag; 2000 Hans Dicken: JDBC; 1.Auflage; Bonn: Internat. Thomson Publ.; 1997 Java Seminar: SQLJ – Embedded SQL in Java von Martin Fuchs http://www.fsai.fh-trier.de/fsai/seminare/archiv/0006/SQLJ.pdf Using Java DataBase Connectivity von Sun Microsystems Inc. http://docs.sun.com/source/816-4685/index.html JDBC TM Data Access API Relationship of JDO and Java TM 2 Platform, Enterprise Edition APIs von Sun Microsystems Inc. http://java.sun.com/products/jdbc/related.html JDBC™ 3.0 Specification von Sun Microsystems Inc. http://java.sun.com/products/jdbc/ Einführung in JDBC – Tutorium zur Internet-Datenbank-Einbindung in Java über JDBC und RMI Datenbanken: Eine Einführung http://www.in.tuclausthal.de/~hoerner/hs_datenbanken/DBEinfuehrung.pdf