Programmierung von Client/ServerAnwendungen Verwendung von API‘s (JDBC) WS06/07 Prof. Dr. Andreas Schmietendorf 1 Übersicht zur Vorlesung Persistenzsicherung von Java-Objekten Datenbankanbindung mit Hilfe von JDBC Beispiel zur Verwendung des JDBC-Interfaces Verwendung von Prepared Statements Weiterführende Themenstellungen zum JDBC-Interface WS06/07 Prof. Dr. Andreas Schmietendorf 2 Möglichkeiten zur Persistenzsicherung von Java-Objekten WS06/07 Prof. Dr. Andreas Schmietendorf 3 Möglichkeiten zur Persistenzsicherung Objektserialisierung – Objekt als Datenstrom wegschreiben Manuelles OR-Mapping - Verwendung des JDBC-Frameworks - Embedded SQL (sehr verbreitet in C bzw. C++, bei Java aber keine Bedeutung) Nutzung objektorientierter Datenbanksysteme Verwendung des DAO-Entwurfsmusters (Datenabstraktion) Einsatz von EJB‘s (Entity Beans) OR-Mapping Tools (z.B. Hibernate) WS06/07 Prof. Dr. Andreas Schmietendorf 4 Möglichkeiten zur Persistenzsicherung A: SQL-Kommando senden Query Engine Client C: Ergebnisse zurückgeben B: Kommando ausführen DatenbankSpeicher RDBMS DB-Server WS06/07 Prof. Dr. Andreas Schmietendorf 5 Java Client Java JDBC Möglichkeiten zur Persistenzsicherung SQL Query Engine Relation Kommando ausführen DatenbankSpeicher RDBMS DB-Server WS06/07 Prof. Dr. Andreas Schmietendorf 6 Java Client Objekte OR-Mapper Möglichkeiten zur Persistenzsicherung JDBC, SQL Query Engine Relation Kommando ausführen DatenbankSpeicher RDBMS DB-Server WS06/07 Prof. Dr. Andreas Schmietendorf 7 Möglichkeiten zur Persistenzsicherung Hibernate-Anwendungen bestehen klassisch aus 4 Teilen: 1. Hibernate-Konfigurationsdatei (XML) 2. Pro persistenter Klasse eine Hibernate Mapping XML-Datei 3. Der Hibernate Java Library (JAR-Datei) 4. HQL (Hibernate Query Language) OO-Erweiterung zu SQL sowie: 1. Den Java-Klassen 2. Der Datenbank mit dem Datenbank Schema WS06/07 Prof. Dr. Andreas Schmietendorf 8 Möglichkeiten zur Persistenzsicherung OR-Mapping Tools: http://www.service-architecture.com/products/object-relational_mapping.html WS06/07 Prof. Dr. Andreas Schmietendorf 9 Datenbankanbindung mit Hilfe von JDBC WS06/07 Prof. Dr. Andreas Schmietendorf 10 Datenbankanbindung mit JDBC JDBC - Java Database Connectivity API zur Programmierung von Datenbankverbindungen (Konzeptionell angelehnt an ODBC) JDBC nutzt für den Datenbankzugriff das durch die X/Open standardisierte Call-Level-Interfaces (CLI) - Low level API, kein direktes objektorientiertes Mapping - Implementierungen von Oracle, Sybase, Informix, DB/2, IMS,... Aufgaben des JDBC-Interface - Verbindungsaufbau zur Datenbank - SQL Kommandos (vgl. SELECT name FROM MITARBEITER) - Ergebnisse verarbeiten und in der Oberfläche anzeigen WS06/07 Prof. Dr. Andreas Schmietendorf 11 Datenbankanbindung mit JDBC Das JDBC-Interface bietet verschiedene Treibertypen (Typ 1 bis 4) - Entscheidung über die Schichten der Applikation - Vorteile einer mehrschichtigen C/S-Architektur berücksichtigen Verwendbare Systeme (ohne Firewall): - Web-Server: MS Internet Information Server - JDBC-Applikations-Server (z.B. Weblogic „Tengah“ www.weblogic.com) - MS SQL-Server WS06/07 Prof. Dr. Andreas Schmietendorf 12 Datenbankanbindung mit JDBC Ethernet Client Web-Browser Server HTTP-Anfrage Web-Server (z.B. MS IIS) (z.B. Netscape) html-Dateien class-Dateien DB-Anfrage JDBC-Server Java-Applet (z.B. IDS-Server) Datensätze Client DB-Server Daten Server WS06/07 Prof. Dr. Andreas Schmietendorf 13 Datenbankanbindung mit JDBC Type 1 Treiber: JDBC-ODBC Bridge - keine Hardwareunabhängigkeit bei Applet-Anwendungen - DB-Zugriffe erfolgen via dem ODBC-Treiber - Zu fast jedem DB-System sind ODBC-Treiber verfügbar Type 2 Treiber: Native partly Java Driver - Treiber des entsprechenden DBMS Herstellers werden benötigt - Wandlung der JDBC-Aufrufe in herstellerspezifische Client-API für das jeweilige Datenbank-System Merke: Treibertypen 1 und 2 sind für Applet-Anwendungen ungeeignet. WS06/07 Prof. Dr. Andreas Schmietendorf 14 Datenbankanbindung mit JDBC Type 3 Treiber: Java Net all Java-Driver - Treiber nur zum Teil in Java geschrieben (eigentlich Proxy beim Client) Middleware zwischen Java-Client und DB-Server notwendig keine spezielle Software beim Client (Applets möglich) notwendig mehrstufige C/S-Architekturen sind realisierbar (n-Tier) Type 4 Treiber: - Treiber komplett in 100% Java geschrieben - Treiber wird bei Start des Browsers übertragen (rel. groß) - Mehrstufige C/S-Architekturen werden unterstützt Schlußfolgerung: Treibertyp 4 ist für mehrstufige C/S-Architekturen die optimale Lösung (z.B. Einsatz im Kontext eines Web-Serves) WS06/07 Prof. Dr. Andreas Schmietendorf 15 Datenbankanbindung mit JDBC SQL-2 Entry Level Standard von 1992 Problem der Portierung einer Anwendung auf ein anderes Datenbanksystem (Problem der verschiedenen SQL-Dialekte) Forderung von SUN an die JDBC-Hersteller zur Sicherung eines minimalen Anspruches auf Standardisierung SUN stellt eine entsprechende Test-Suite zum Nachweis der Konformität von JDBC-Treibern bereit Kritisch ist die Verwendung von Funktionen die über den o.g. Standard hinausgehen WS06/07 Prof. Dr. Andreas Schmietendorf 16 Datenbankanbindung mit JDBC Meistgenutzte Klassen des JDBC-API (import java.sql.*) - java.sql.DriverManager Verwalten der Datenbankverbindung - java.sql.DriverConnection Verbindungsaufbau zur Datenbank - java.sql.Statement beinhaltet den auszuführenden SQL-Befehl wird als ASCI-Zeichenkette übergeben - java.sql.ResultSet Zugriff auf die Ergebnismenge des ausgeführten SQL-Befehls WS06/07 Prof. Dr. Andreas Schmietendorf 17 Datenbankanbindung mit JDBC Öffnen einer Verbindung Bevor auf die DB zugegriffen werden bedarf es einer Verbindung Schritte beim Verbindungsaufbau - Datenbanktreiber laden - Initialisierung des Datenbanktreibers - Erzeugen eines Verbindungsobjektes Verbindungsobjekt - Bleibt während der gesamten Verbindung bestehen - Lieferant für spezielle Objekte zur Abfrage & Veränderung der DB WS06/07 Prof. Dr. Andreas Schmietendorf 18 Datenbankanbindung mit JDBC Ausprägungen von getConnection (Verbindungsaufbau zur Datenbank) static Connection getConnection( string url ) static Connection getConnection( string url, String user, String password ) static Connection getConnection( string url, Properties info ) WS06/07 Prof. Dr. Andreas Schmietendorf 19 Datenbankanbindung mit JDBC Aufbau des Connection-Strings: Besteht aus mehreren Teilen Durch Doppelpunkt voneinander getrennt 1. Teil: immer jdbc 2. Teil: Sub-Protokoll – Angabe des konkreten Treibers Weitere Teile: Treiberspezifisch Beispiele: Firebird-DB con = DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:DirDB","sysdba","masterkey"); MySQL-DB con = DriverManager.getConnection("jdbc:mysql://localhost/hs_mitarbeiter", "root", ""); WS06/07 Prof. Dr. Andreas Schmietendorf 20 Datenbankanbindung mit JDBC Erzeugen von Anweisungsobjekten Abfragen und Änderungen erfolgen mittels Anweisungsobjekten Implementieren das Interface Statement bzw. entspr. Subinterfaces Einfachste Form „createStatement“ mit folgenden Methoden - executeQuery (String sql) - executeUpdate (String sql) Erzeugung unparametrisierter Abfragen und Änderungen der DB Rückgabe: - Einfacher numerischer Ergebniswert (Erfolg bzw. Misserfolg) - Menge von Datenbanksätzen, als Ergebnis der Abfrage WS06/07 Prof. Dr. Andreas Schmietendorf 21 Datenbankanbindung mit JDBC Statement-Objekte: Häufig kostenintensive Ressourcen - Belegung von Speicherplatz - Belegung von Rechenzeit Erzeugung einer großen Anzahl sollte vermieden werden Besserer Stil: - Anlegen einer Reihe vordefinierter Statement-Objekte - Mehrfache Verwendung von Statement-Objekten - Allerdings besteht die Gefahr undefinierter Zustände WS06/07 Prof. Dr. Andreas Schmietendorf 22 Datenbankanbindung mit JDBC Datenbankabfragen – Verwendung der executeQuery-Methode: public ResultSet executeQuery (String sql) throws SQLException Die oben dargestellte Methode erwartet eine für die Datenbank gültige SELECT-Anweisung (z.B. SELECT * FROM kunden WHERE name = ‘Meier‘) und gibt einen ResultSet zurück. Das ResultSet repräsentiert die Ergebnismenge. Schrittweisen durchlaufen des ResultSet mittels der Methode next. boolean next() WS06/07 Prof. Dr. Andreas Schmietendorf 23 Datenbankanbindung mit JDBC Datenbankabfragen – Verwendung der executeQuery-Methode: Zugriff auf die Spalten des durch next referenzierten Tupels - getXXX (int n), Übergabe eines numerischen Wertes - getXXX (String x), Übergabe eines Spaltennamens Ausgewählte Get-Methoden von ResultSet - getBoolean - getByte - getDate - getString - getInt WS06/07 Prof. Dr. Andreas Schmietendorf 24 Datenbankanbindung mit JDBC Datenbankänderungen – Verwendung der executeUpdate-Methode: public int executeUpdate (String sql) throws SQLException Die oben dargestellte Methode erwartet eine für die Datenbank gültige INSERT, UPDATE oder DELETE-Anweisung (z.B. INSERT INTO kunden VALUES (122, ‘Meier‘, ‘Andreas‘, 13509, ‘Berlin‘, ‘Wittestrasse 30H‘) bzw. eine DDL-Anweisung zum Ändern der Datenbankstruktur. Diese Methode gibt keine Ergebnismenge zurück! Bei Erfolg wird 1 zurückgegeben, andernfalls eines SQLException WS06/07 Prof. Dr. Andreas Schmietendorf 25 Datenbankanbindung mit JDBC Klasse SQLException (Ausnahmebehandlung): Verbindungsaufbau zur Datenbank ist fehlgeschlagen Probleme mit SQL-Anweisungen - Syntaxfehler - Semantische Fehler – z.B. falsche Typisierung Behandlung einer SQLException catch (SQLException sqle) while (sqle != null) { System.err.println(sqle.toString()); System.err.println(“SQL-Status: “ + sqle.getSQLState()); System.err.println(“ErrorCode: “ + sqle.getSQLState()); } } WS06/07 Prof. Dr. Andreas Schmietendorf 26 Beispiel für die Verwendung des JDBC-Interfaces WS06/07 Prof. Dr. Andreas Schmietendorf 27 JDBC-Beispiel Benötigte Software bzw. Systeme: Laufende Firebird-Datenbank (z.B. mittels IBO-Console bearbeiten) http://sourceforge.net/projects/firebird “firebird-jca-jdbc-driver” firebirdsql-full.jar – enthält alle benötigten Klassen - firebirdsql.jar - mini-concurrent.jar - jaas.jar (Innerhalb des JDK 1.4) - mini-j2ee.jar (JDBC classes) - log4j-core.jar (Logging-Funktionalitäten) JDK 1.4.x - Setzen der Java-Umgebungsvariablen - Unter WinXP: Start – Einstellungen – Systemsteuerung – System - Erweitert - CLASSPATH .;C:\j2sdk1.4.2_08\lib\firebirdsql-full.jar - JAVA_HOME C:\j2sdk1.4.2_08 WS06/07 Prof. Dr. Andreas Schmietendorf 28 JDBC-Beispiel Firebank-Datenbank mittels DDL aufsetzen Java-Programm implementieren - Treiber laden Class.forName("org.firebirdsql.jdbc.FBDriver"); - Variable für Connection-Objekt: private Connection con; - Datenbankverbindung (Treiber:Server:Datenbank) herstellen mit: DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:C:/Pro gramme/Firebird/examples/employee.gdb","sysdba","masterkey"); - Treiber: jdbc:firebirdsql - Server: localhost/3050 - Datenbank: C:/Programme/Firebird/examples/employee.gdb - Nutzername/Passwort: sysdba/masterkey WS06/07 Prof. Dr. Andreas Schmietendorf 29 JDBC-Beispiel WS06/07 Prof. Dr. Andreas Schmietendorf 30 JDBC-Beispiel import java.sql.*; public class JDBCTest { // A. Schmietendorf – Fachhochschule für Wirtschaft Berlin – WS06/07 // JDBC-Testbeispiel im Rahmen der Vorlesung Programmierung C/S-Systeme private Connection con; private java.sql.Statement stm; public static void main(String argv[]) { new JDBCTest().access(); } WS06/07 Prof. Dr. Andreas Schmietendorf 31 JDBC-Beispiel public void access() { try { Class.forName("org.firebirdsql.jdbc.FBDriver"); } catch(ClassNotFoundException ex) { System.out.println("Class.forName : " + ex.getMessage()); } try { con = DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:C:/Programme/Firebird/ examples/employee.gdb","sysdba","masterkey"); stm = con.createStatement(); stm.executeUpdate("INSERT INTO country VALUES ('Bulgaria','Leva')"); System.out.println("Daten erfolgreich in die Datenbank eingetragen"); WS06/07 Prof. Dr. Andreas Schmietendorf 32 JDBC-Beispiel System.out.println("Daten aus der Datenbanktabelle auslesen"); ResultSet rs = stm.executeQuery ("SELECT * FROM country"); while (rs.next ()) { String country = rs.getString (1); String currency = rs.getString (2); System.out.println(country + " " + currency); } System.out.println("Ende der Datenausgabe - A. Schmietendorf"); // Ressourcenffreigabe rs.close(); con.close(); } catch (SQLException ex) { System.out.println(ex.getMessage()); } } } WS06/07 Prof. Dr. Andreas Schmietendorf 33 JDBC-Beispiel Verwendung eines ResultSet-Objektes zur Ergebnisverwaltung der Anfrage Navigation über die Ergebnismenge erfolgt nach dem Cursor-Prinzip Weitersetzen des Cursors mit der Methode next Zeilenauswahl entspricht der aktuellen Position des Cursors Spaltenauswahl der aktuellen Tupel mit getXXX-Methode und Spaltenindex ResultSet rs = stm.executeQuery ("SELECT * FROM country"); while (rs.next ()) { String country = rs.getString (1); String currency = rs.getString (2); System.out.println(country + " " + currency); } WS06/07 Prof. Dr. Andreas Schmietendorf 34 JDBC-Beispiel WS06/07 Prof. Dr. Andreas Schmietendorf 35 Verwendung von Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 36 Prepared Statements Prepared Statements sind parametrisierte SQL-Anweisungen Werden deklariert und zum Vorkompilieren der DB übergeben Können später beliebig of ausgeführt werden Vorteile: - Vorbereitungssarbeiten werden nur einmal erledigt • Syntaxanalyse • Vorbereitung der Abfragestrategie und -optimierung - Bessere Performance JDBC Prepared Statements im Interface PreparedStatement WS06/07 Prof. Dr. Andreas Schmietendorf 37 Prepared Statements Methode preparedStatement: PreparedStatement pst = con.preparedStatement ( “SELECT * FROM ?“ ); Parametrisierung von executeQuery bzw. executeUpdate - Aufruf einer entsprechenden set-Methode je Fragezeichen Ausführung mittels executeQuery bzw. executeUpdate WS06/07 Prof. Dr. Andreas Schmietendorf 38 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 39 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 40 Prepared Statements public class DBClient { public static void main(String[] args) throws Exception { DBConnect MyDBConnect = new DBConnect(); // Suche ueber den Namen String res1 = MyDBConnect.searchForName("Mueller"); System.out.print(res1); // Suche ueber die email-Adresse String res2 = MyDBConnect.searchForEMail("[email protected]"); System.out.print(res2); // Suche ueber die Raumnummer String res3 = MyDBConnect.searchForRaum("113"); System.out.print(res3); } } WS06/07 Prof. Dr. Andreas Schmietendorf 41 Prepared Statements public class DBClient { public static void main(String[] args) throws Exception { DBConnect MyDBConnect = new DBConnect(); // Suche ueber den Namen String res1 = MyDBConnect.searchForName("Mueller"); System.out.print(res1); // Suche ueber die email-Adresse String res2 = MyDBConnect.searchForEMail("[email protected]"); System.out.print(res2); // Suche ueber die Raumnummer String res3 = MyDBConnect.searchForRaum("113"); System.out.print(res3); } } WS06/07 Prof. Dr. Andreas Schmietendorf 42 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 43 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 44 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 45 Prepared Statements WS06/07 Prof. Dr. Andreas Schmietendorf 46 Weiterführende Themenstellungen zum JDBC-Interface WS06/07 Prof. Dr. Andreas Schmietendorf 47 Transaktionssicherung Steuerung des Transaktionsverhalten der Datenbank über 3 Methoden des Connection-Objektes - void commit() - void rollback() - void setAutoCommit (boolean autoCommit) Nach dem Aufbau einer JDBC-Verbindung - DB im Auto-Commit-Modus (Vorgabe JDBC) - Jede einzelne Anweisung gilt als separate TA Änderung mittes setAutoCommit (false) - TA müssen explizit durch Aufruf von commit bestätigt werden - Mittels rollback kann eine TA zurückgesetzt werden WS06/07 Prof. Dr. Andreas Schmietendorf 48 Transaktionssicherung Transaction Isolation Level (Beeinflussung des Sperrverhalten) - Steuerung des Grades der Parallelität - Hoher Transaction Level desto weniger Konsistenzprobleme geringerer Durchsatz, d.h. Performanceprobleme - Niedriger Tranaction Level ggf. potentielle Konsistenzprobleme besseres Performanceverhalten WS06/07 Prof. Dr. Andreas Schmietendorf 49 Transaktionssicherung Verfügbare Transaction Isolation Level - Connection.TRANSACTION_NONE - Connection.TRANSACTION_READ_UNCOMMITTED - Connection.TRANSACTION_READ_COMMITTED - Connection.TRANSACTION_REPEATABLE_READ - Connection.TRANSACTION_SERIALIZABLE Lesen und Ändern des Transaction Isolation Level - int getTransactionIsolation ( ) - void setTransactionIsolation ( ) WS06/07 Prof. Dr. Andreas Schmietendorf 50