Java Database Connectivity-API (JDBC) Motivation Design Grundlagen Typen Metadaten Transaktionen JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 1 Motivation Problem: Zugriff auf ein DBMS ist Herstellerabhängig Anwendung Anwendung Anwendung MySQL API MySQL DB2 API DB2 Oracle API Oracle JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 2 Motivation Lösung: Zwischenschicht MySQL API Anwendung JDBC API JDBC MySQL DB2 API DB2 Oracle API Oracle JDBC Treiber JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 3 Design Entwicklung seit: 1995 Erster Ansatz: Java erweitern Zweiter Anzatz: Treiber der Datenbankhersteller Vorbild: ODBC Unterschiede: • ODBC wenige Befehle, viele Optionen • JDBC viele einfache Methoden • ODBC nutzt void-Zeiger • Java kennt keine Zeiger Flexibilität: JDBC erlaubt beliebige Zeichenfolgen • Anpassung an Datenbank möglich. - Optimierung - Bindung JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 4 Design Java Anwendung JDBC-Treibermanager JDBC/ODBC -Brücke JDBCTreiber ODBCTreiber Datenbank Datenbank JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 5 Treiber Typ 1: JDBC/ODBC-Brücke ODBC ist sehr weit verbreitet Leistung Wartung Testen, Experimentieren kein JDBC Treiber verfügbar Windows Plattformen JDBCAnwendung ODBC Brücke • • • • • • DB Client Server Typ 2: Partial Java Driver • • • • konvertiert JDBC Aufruf in DB abhängigen API Aufruf schnell, weil API Aufruf kompiliert ist A DB + OS abhängig JDBCP Nutzer braucht plattformabhängige API Anw. I Client DB Server JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 6 Treiber Typ 3: Reiner Java Treiber zu Middleware • • • • Keine plattformabhängigen Treiber am Client DB unabhängig JDBCFlexibel, mehrere DB möglich Anw. DB abhängiger Code in Middleware Client M W DB Server Server Typ 4: Reiner Java Treiber direkt zur DB • • • • JDBC in DB spezifische Netzwerkaufrufe verpackt Schnell Keine plattformabhängigen Treiber am Client Client braucht für verschiedene DB verschiedene Treiber JDBCAnw. DB Client Server JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 7 Treiberinstallation Download • http://developers.sun.com/product/jdbc/drivers • Datenbankhersteller Installation • Eintragen in den Klassenpfad Registrieren • Bei dem Programmstart durch Parameter: - java –Djdbc.drivers=com.mysql.jdbc.Driver <Programm> • Setzen der Systemeigenschaft "jdbc.drivers": - System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver"); • Händisches Instanzieren der Treiber-Klasse: - Class.forName("com.mysql.jdbc.Driver"); JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 8 Verbindungsaufbau Verbindungsaufbau erfolgt mit • Url zur Datenbank • Benutername, Passwort Datenbank Url • jdbc:<Datenbanktreiber>:<treiberspezifische Angaben> • MySql: - jdbc:mysql://<host>:<port>/< Datenbankname> • JavaDB (Derby): - jdbc:derby:/path/to/Database - jdbc:derby:Database JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 9 Grundlagen: DriverManager DriverManager • Verwaltet registrierte Treiber • Aufbau von Verbindungen getConnection(String url, url, String user, user, String password) password) - Liefert eine Connection zu der gegebenen url wenn ein passender Treiber registriert ist. /* Registrieren des Treibers */ Class.forName("com.mysql.jdbc.Driver").newInstance(); /* Anfordern einer Datenbankverbindung */ Connection con = DriverManager.getConnection(url, user, pass); JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 10 Grundlagen: Connection Connection: Verwaltet die Verbindung (Session) zu einer Datenbank. • close() - Schließen der Verbindung • commit() - Bestätigen alle bisher vorgenommenen Änderungen, standard ist auto-commit • Statement createStatement() - Erzeugt ein Statement mit dem SQL-Statements an die Datenbank abgegeben werden können. Statement stat = con.createStatement(); stat.executeUpdate("INSERT INTO test VALUES ('Hallo')"); • PreparedStatement prepareStatement(String sql) - Erzeugt Statements welche von der Datenbank vorkompiliert werden können. PreparedStatement stat; stat = con.prepareStatement("INSERT INTO test VALUES ('Welt')"); ... stat.executeUpdate(); JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 11 Grundlagen: Statement Keine Paramerter verwenden! Stichwort: SQL-Injection Statement: • ResultSet executeQuery(String sql) - Ausführen einer SQL Abfrage (SELECT) • int executeUpdate(String sql) - Ausführen eines Updates (UPDATE, INSERT, DELETE, CREATE). - Rückgabewert zeigt die Anzahl der betroffenen Zeilen. • boolean execute(String sql) - Ausführen einer beliebigen SQL Anweisung. - Rückgabewert Zeigt an ob eine Ergebnismenge geliefert wurde. • int getUpdateCount() - Anzahl der von der letzten Anweisung betroffenen Zeilen oder -1 wenn die Anweisung keinen Zähler hatte. • ResultSet getResultSet() - Ergebnismenge der letzten Abfrage oder null wenn wenn die Anweisung keine Ergebnismenge hatte. JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 12 Grundlagen: PreparedStatement PreparedStatement: Absetzen von vorkompilierten Statements. • void set<Typ>(int n, <Typ> x) - Setzen des Parameters an der Stelle n (1 .. m). • void clearParameters() - Löschen aller Parameterwerte. • ResultSet executeQuery() - Ausführen der vorkompilierten SQL Abfrage (SELECT) • int executeUpdate() - Ausführen des vorkompilierten Updates (UPDATE, INSERT, DELETE, CREATE). - Rückgabewert zeigt die Anzahl der betroffenen Zeilen. PreparedStatement stat; stat = con.prepareStatement("INSERT INTO test VALUES (?)"); stat.setString(1, "Hallo"); stat.executeUpdate(); stat.setString(1, "Welt!"); stat.executeUpdate(); JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 13 Grundlagen: Callable Statement CallableStatement: Ausfüren von Datenbankprozeduren (SQL stored procedures) über spezielle SQL strings: • • • • Parameterlose Prozedur: {call procedure_name} Prozedur: {call procedure_name[(?, ?, ...)]} Funktion: {? = call procedure_name[(?, ?, ...)]} Das setzen der Parameter erfolgt analog zu den PreparedStatements JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 14 Grundlagen: ResultSet ResultSet: Ermöglicht das zeilenweise Abarbeiten der Ergebnistabelle. • boolean next() - Anspringen der nächsten Zeile, begonnen wird vor der ersten Zeile. - true solange noch eine gültige Zeile erreicht wurde. • <Typ> get<Typ>(int spalte) • <Typ> get<Typ>(String spaltenName) • int findColumn(String spaltenName) getString(3) => 25 getString("Name") => Max findColumn("Nr") => 1 next() Nr 1 2 ... Name Max Kurt ... Age 25 27 ... JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 15 Grundlagen: ResultSet Fortsetzung • boolean first() - Erste Zeile im ResultSet. - true wenn eine gültige Zeile erreicht wurde. • beforeFirst() - Vor die erste Zeile im ResultSet. • boolean last() - Letzte Zeile im ResultSet. - true wenn eine gültige Zeile erreicht wurde. • afterLast() - Nach letzter Zeile im ResultSet. • boolean absolute(int row) - Eine Zeile anspringen row > 0 ... von oben gezählt (1 erste Zeile, 2 zweite Zeile, ...) row < 0 ... von unten gezählt (-1 letzte Zeile, -2 vorletzte Zeile, ...) - true wenn eine gültige Zeile erreicht wurde. • int getRow() - Nummer der aktuellen Zeile JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 16 Grundlagen: Beispiel ResultSet Wie viele Zeilen hat ein ResultSet? Connection con; ... Statement stat = con.createStatement(); ResultSet result = stat.executeQuery("SELECT ..."); int rowAmount; result.last(); rowAmount = result.getRow(); result.beforeFirst(); // Mit ResultSet arbeiten while (result.next()) { ... } JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 17 Typen Standard-Typemapping zwischen SQL und JAVA SQL Type Java Type CHAR, VARCHAR, LONGVARCHAR String NUMERIC, DECIMAL java.math.BigDecimal BIT boolean TINYINT byte SMALLINT short INTEGER int BIGINT long REAL float FLOAT, DOUBLE double BINARY, VARBINARY, LONGVARBINARY byte[] DATE java.sql.Date TIME java.sql.Time TIMESTAMP java.sql.Timestamp JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 18 Metadaten Beschreibung der Struktur der Datenbank und deren Tabellen DatabaseMetaData: • <Connection>.getMetaData() • ResultSet getTables(String catalog, String schema, String table, String[] types) • ResultSet getColumns(String catalog, String schema, String table, String column) - catalog: Name des Katalogs "" Tabellen ohne Katalog, null Katalognamen nicht berücksichtigen - scheme: Schemaname "" Tabellen ohne Schema, null nicht berücksichtigen - table: Tabellenname null nicht berücksichtigen - column: Spaltenname null nicht berücksichtigen - types: Typische namen: "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM" JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 19 Metadaten ResultSetMetaData: Nr 1 2 ... • <ResultSet>.getMetaData() • int getColumnCount() - Anzahl der Spalten im ResultSet. • • • • • Name Title ... Max Mag. ... Kurt DI ... ... ... Age 25 27 ... String getColumnName(int column) int getColumnType(int column) String getColumnTypeName(int column) SELECT Nr, Name, Age String getTableName(int column) FORM users; ... getColumnCount() => 3 getColumnName(1) => "Nr" getColumnType(3) => 4 getColumnTypeName(3) => "int" getTableName(2) => "users" Nr 1 2 ... Name Age Max 25 Kurt 27 ... ... JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 20 Transaktionen Auto Commit: Jede Anweisung ist eine abgeschlossene Transaktion. • Abfragen: - <Connection>.getAutoCommit() • Setzen: - <Connection>.setAutoCommit(bool) Abschliessen einer Transaktion: • <Connection>.commit() Rücksetzen im Fehlerfall (z.B.: SQLException): • <Connection>.rollback() Connection con; ... try { con.setAutoCommit(false); Statement stat = con.createStatement(); stat.executeUpdate("INSERT ..."); stat.executeUpdate("INSERT ..."); stat.executeUpdate("UPDATE ..."); con.commit(); } catch (SQLException e) { con.rollback(); } JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 21 Zusammenfassung Datenbankunabhängigkeit • Zwischenschicht • Treiberschnittstelle (mind. SQL 92) - 4 Treiberarten: JDBC -> ODBC Teilweise Java Nur Java zu einer Middleware Nur Java zur Datenbank • Einfachere Programmentwicklung Beliebige SQL-Kommandos absetzbar • Optimierung / Datenbankabhängigkeit Arten von Statements • java.sql.Statement - Statisch oder vom Benutzer frei wählbar (Achtung: SQL injection) • java.sql.PreparedStatement - Vorbereitete Statements (Sicher gegen SQL injection, schnell) • java.sql.CallableStatement - Ausführen von SQL stored procedures JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 22 Neuerungen in JDBC 4.0 (Java 6.0) Spezifiziert in JSR-221 Automatisches Laden des Treibers beim Verbindungsaufbau SQL:2003 Unterstützung großer Objekte (CLOB, BLOB) Mehr Datentypen (SQLXML) Neue Exceptions • • • • SQLTransientException SQLRecoverableException SQLNonTransientException V JavaDB (Derby) JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 23 Java Typ JDBC Typ (PreparedStatement) JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network JSR 221, JDBC Specification 4, November 7, 2006, Page 198 Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 24 JDBC Typ Java Typ (ResultSet) JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network JSR 221, JDBC Specification 4, November 7, 2006, Page 199 Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 25 Arbeiten mit Derby Umgebungsvariablen • JAVA_HOME= Pfad zur Java-Installation • DERBY_INSTALL=%JAVA_HOME%\db • CLASSPATH + %DERBY_INSTALL%\lib\derby.jar + %DERBY_INSTALL%\lib\derbytools.jar • PATH + %JAVA_HOME%\db\frameworks\embedded\bin Systeminformationen • java org.apache.dery.tools.sysinfo JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 26 Arbeiten mit Derby Kommandozeilenwerkzeug • java org.apache.derby.tools.ij Verbinden zu, und erzeugen einer Datenbank Erzeugen einer Tabelle Beschreibung einer Tabelle JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 27 Arbeiten mit Derby Abfragen von Datensätzen Aktualisieren eines Datensatzes Löschen einer Tabelle JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer 28