Java Database Connectivity-API (JDBC) Motivation Design Grundlagen Typen Metadaten Transaktionen Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 1
Motivation Problem: Zugriff auf ein DBMS ist Herstellerabhängig Anwendung Anwendung MySQL API DB2 API MySQL DB2 Anwendung Oracle API Oracle Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 2
Motivation Lösung: Zwischenschicht MySQL API MySQL Anwendung JDBC API JDBC DB2 API DB2 Oracle API Oracle JDBC Treiber 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 Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 4
Design Java Anwendung JDBC-Treibermanager JDBC/ODBC -Brücke JDBC- Treiber ODBC- Treiber Datenbank Datenbank 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 JDBC- Anwendung Client Brücke ODBC DB Server Windows Plattformen Typ 2: Partial Java Driver konvertiert JDBC Aufruf in DB abhängigen API Aufruf schnell, weil API Aufruf kompiliert ist DB + OS abhängig Nutzer braucht plattformabhängige API JDBC- Anw. A P I DB Client Server 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 Flexibel, mehrere DB möglich DB abhängiger Code in Middleware JDBC- Anw. M W DB Client 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 JDBC- Anw. Client DB Server 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"); 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 Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 9
Grundlagen: DriverManager DriverManager Verwaltet registrierte Treiber Aufbau von Verbindungen getconnection(string url, String user, String 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); 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(); Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 11
Grundlagen: Statement 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. Keine Paramerter verwenden! Stichwort: SQL-Injection - 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. 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(); 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 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 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 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()) { } Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 17
Typen Standard-Typemapping zwischen SQL und JAVA SQL Type CHAR, VARCHAR, LONGVARCHAR NUMERIC, DECIMAL BIT TINYINT SMALLINT INTEGER BIGINT REAL FLOAT, DOUBLE BINARY, VARBINARY, LONGVARBINARY DATE TIME TIMESTAMP Java Type String java.math.bigdecimal boolean byte short int long float double byte[] java.sql.date java.sql.time java.sql.timestamp 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" Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 19
Metadaten ResultSetMetaData: <ResultSet>.getMetaData() int getcolumncount() - Anzahl der Spalten im ResultSet. String getcolumnname(int column) int getcolumntype(int column) String getcolumntypename(int column) String gettablename(int column) Nr 1 2 Name Max Kurt Title Mag. DI Age 25 27 SELECT Nr, Name, Age 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 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(); } 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 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 JavaDB (Derby) Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 23
Java Typ JDBC Typ (PreparedStatement) 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) 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 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 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 Pratikum SWE 2 M. Löberbauer, T. Kotzmann, H. Prähofer 28