© Holger Röder Winter 2008/2009 Programmentwicklung se Java: Kapitel 8 Datenbankzugriff mit JDBC Programmentwicklung WS 2008/2009 Holger Röder [email protected] © Holger Röder Winter 2008/2009 Programmentwicklung se Überblick über Kapitel 8 Einführung in SQL und JDBC Verbindung zur Datenbank Einfache SQL-Anweisungen Datenbankabfragen Datenbankänderungen Weiterführende Themen Prepared Statements SQL-Ausnahmen Transaktionen Java DB 2 © Holger Röder Winter 2008/2009 Programmentwicklung se Structured Query Language (SQL) SQL ist eine weit verbreitete Datenbanksprache zur Erzeugung, Änderung und Abfrage von Daten in relationalen Datenbanken. Beispiel: Tabelle erzeugen CREATE TABLE person (vorname VARCHAR(30), nachname VARCHAR(30), alterJahre INTEGER) vorname nachname alterJahre Leonie Lehmann 22 Gustav Graf 46 Einfügen in die Datenbank INSERT INTO person (vorname, nachname, alterJahre) VALUES ('Leonie', 'Lehmann', 22) INSERT INTO person VALUES ('Gustav', 'Graf', 46) Abfrage SELECT * FROM person WHERE alterJahre < 30 liefert 1 Eintrag 3 © Holger Röder Winter 2008/2009 Programmentwicklung se Java Database Connectivity (JDBC) Seit Java 1.1 existiert mit Java Database Connectivity (JDBC) eine einheitliche Datenbankschnittstelle für Java-Programme. JDBC ist eine Schnittstelle zwischen der (in aller Regel relationalen) Datenbank und der Anwendung, die auf sie zugreifen will. JDBC stellt ein Call Level Interface dar: SQL-Befehle werden in der Anwendung als normale Zeichenketten behandelt und als Parameter spezieller Methoden an die Datenbank übermittelt. Die Rückgabewerte der Methoden (Daten, Statuscodes) werden dann von der Anwendung ausgewertet und weiterverarbeitet. 4 © Holger Röder Winter 2008/2009 Programmentwicklung se JDBC-Treiber Der jeweilige JDBC-Treiber ist datenbankspezifisch. Für alle relevanten SQL-Datenbanken stehen JDBC-Treiber zur Verfügung. gleiche JavaProgrammierAnwendung schnittstelle MySQL JDBCTreiber MySQL-Datenbank Oracle JDBCTreiber Oracle-Datenbank Die passende JDBC-Treiberbibliothek muss (typischerweise als .jar-Archiv) im Klassenpfad (classpath) vorhanden sein. Das Paket java.sql enthält die JDK-Klassen für den JDBC-Zugriff. 5 © Holger Röder Winter 2008/2009 Programmentwicklung se JDBC-Treiber laden Bis einschließlich Java 5 muss vor dem Verbindungsaufbau der zur Datenbank passende JDBC-Treiber geladen werden. Dies kann über die Klasse Class erfolgen. Klassenname MySQL: muss bekannt Class.forName("com.mysql.jdbc.Driver"); sein. Apache Derby/Java DB (Embedded Mode): Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Oracle 8i: Class.forName("oracle.jdbc.driver.OracleDriver"); Ab Java 6 (mit JDBC 4.0) entfällt das explizite Laden des JDBCTreibers. Beim ersten Verbindungsaufbau zur Datenbank wird der Treiber automatisch gesucht und geladen. 6 © Holger Röder Winter 2008/2009 Programmentwicklung se Verbindungsaufbau zur Datenbank Mit der statischen Methode getConnection() der Klasse DriverManager kann eine Verbindung zur Datenbank hergestellt werden: Connection c = DriverManager.getConnection("jdbc:derby:TestDB"); ... c.close(); // Verbindung schließen Connection-String Connection-Objekt repräsentiert die Verbindung zur DB Connection-String: "jdbc:Treiber:DB-spezifische Teile" Variante von getConnection() mit Angabe von Benutzername und Passwort: Connection c = DriverManager.getConnection( "jdbc:oracle:oci:@OracleTest", "user", "password"); Connection-String für Oracle-Datenbank 7 © Holger Röder Winter 2008/2009 Programmentwicklung se Einfache SQL-Abfragen Abfragen und Änderungen der Datenbank erfolge über StatementObjekte (Objekte, die die Schnittstelle Statement implementieren). createStatement() liefert ein einfaches, nicht parametrisierbares Statement-Objekt zurück. SQL-Abfragen (SELECT) können über executeQuery() ausgeführt werden und liefern ein ResultSet-Objekt mit dem Ergebnis zurück. ... // ggf. JDBC-Treiber laden, Connection-Objekt c holen Statement s = c.createStatement(); Statement-Objekt holen String sql = "SELECT vorname, name, id " + "FROM mitarbeiter " + SQL-Abfrage ausführen "WHERE vorname = 'Carla'"; ResultSet result = s.executeQuery(sql); Über Ergebnis iterieren while (result.next()) { String vorname = result.getString(1); getXXX(spalte) String nachname = result.getString(2); liefert entsprechenden Spaltenwert int id = result.getInt(3); System.out.format("%s %s (id=%d)%n", vorname, nachname, id); } result.close(); // Result-Objekt schließen 8 © Holger Röder Winter 2008/2009 Programmentwicklung se Einfache SQL-Änderungen Änderungen an der Datenbank (INSERT, DELETE, UPDATE) werden über die Methode executeUpdate() durchgeführt. ... String sql1 = "DELETE " + "FROM mitarbeiter " + "WHERE vorname = 'Carla'"; int result1 = s.executeUpdate(sql1); Änderung durchführen: executeUpdate() liefert als Rückgabewert die Zahl der geänderten Zeilen zurück. String sql2 = "INSERT INTO mitarbeiter (vorname, nachname)" + "VALUES ('Sarah', 'Schmidt')"; int result2 = s.executeUpdate(sql2); String sql3 = "UPDATE mitarbeiter " + "SET vorname='Sandra' " + "WHERE vorname = 'Sarah' AND nachname = 'Schmidt'"; int result3 = s.executeUpdate(sql3); ... s.close(); // Statement schließen c.close(); // Verbindung schließen 9 © Holger Röder Winter 2008/2009 Programmentwicklung se Prepared Statements Parametrisierte SQL-Anweisungen werden Prepared Statements Platzhalter ? genannt. Prepared Statements werden zunächst mit Platzhaltern definiert: PreparedStatement p = c.prepareStatement( "INSERT INTO ankunft (vorname, nachname, zeit) VALUES (?, ?, ?)"); Vor der Ausführung des Prepared Statements werden die Platzhalter dann durch konkreten Werte ersetzt: setXXX(n, wert) setzt konkreten p.setString(1, "Emil"); Wert für n-ten Platzhalter p.setString(2, "Erler"); p.setTime(3, new Time(Calendar.getInstance().getTimeInMillis())); p.executeUpdate(); Vorteile von Prepared Statements Übersichtlichkeit, Wiederverwendbarkeit, Sicherheit Bequeme Angabe verschiedener Datenformate: setString(), setInt(), setDate(), setBlob() etc. Datenbank-Performance 10 © Holger Röder Winter 2008/2009 Programmentwicklung se Ausnahmebehandlung Tritt im Zusammenhang mit dem Datenbankzugriff ein Fehler auf, wird eine Ausnahme vom Typ SQLException (oder einer Unterklasse) geworfen. Typische „Auslöser“ einer SQLException: Keine Verbindung zur Datenbank möglich Fehlerhafte SQL-Syntax Methoden: getErrorCode() – liefert den herstellerspezifischen Fehlercode getSQLState() – liefert den SQL-Zustandscode getNextException() – SQLExceptions können verkettet werden; diese Methode liefert das nächste SQLException-Objekt zurück (oder null) try { c = DriverManager.getConnection("jdbc:derby:TestDB"); } catch (SQLException e) { System.err.println("Keine Verbindung zur Datenbank möglich"); System.err.println("Fehlercode: " + e.getErrorCode()); } 11 © Holger Röder Winter 2008/2009 Transaktionen Standardmäßig wird jede einzelne SQL-Anweisung als separate Transaktion angesehen und sofort ausgeführt (Auto-Commit-Modus). Häufig sollen jedoch mehrere aufeinander folgende Datenbankanweisungen zusammengefasst als eine Transaktion ausgeführt werden („ganz oder gar nicht“). Connection c = ... Auto-Commit-Modus abschalten c.setAutoCommit(false); Statement s = c.createStatement(); Programmentwicklung // Typisches Transaktionsbeispiel: // Banküberweisung von Konto A nach Konto B se int kontostandA = kontostandA – 500; int kontostandB = kontostandB + 500; s.executeUpdate("UPDATE konto " + "SET kontostand = " + kontostandA + " WHERE kontoname = 'A'"); s.executeUpdate("UPDATE konto " + "SET kontostand = " + kontostandB + " WHERE kontoname = 'B'"); c.commit(); Transaktion "committen" (SQL-Anweisungen ausführen) 12 © Holger Röder Winter 2008/2009 Java DB / Apache Derby Java DB ist eine leichtgewichtige relationale Datenbank und Bestandteil von Java 6. Java DB ist die von Sun unterstützte Variante der Open-SourceSoftware Apache Derby. Eigenschaften: 100% in Java implementiert Geringer Speicherbedarf (.jar nur ~2 MB) Embedded-Modus, direkte Einbettung in die Java-Applikation Programmentwicklung http://db.apache.org/derby se 13 © Holger Röder Winter 2008/2009 Programmentwicklung se Einbindung von Java DB in ein Java-Projekt Einbindung der Derby-Bibliothek in ein Java-Projekt in Eclipse: Menü Project Æ Properties Æ Abschnitt Java Build Path Æ Button Add External JARs… Bibliothek derby.jar im Pfad [derby-dir]/lib einbinden Die Bibliothek derby.jar ist Teil des JDK; alternativ ist sie unter http://db.apache.org/derby/derby_downloads.html verfügbar. 14 © Holger Röder Winter 2008/2009 Programmentwicklung se Java DB und JDBC Stammverzeichnis für DB-Dateien setzen System.setProperty("derby.system.home", "C:/pe/db"); // Java 5: Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); Connection c = DriverManager.getConnection( "jdbc:derby:TestDB;create=true"); create=true: DB wird erzeugt, wenn sie noch nicht existiert Statement s = c.createStatement(); // Tabelle person anlegen s.executeUpdate("CREATE TABLE person " + "(vorname VARCHAR(30), nachname VARCHAR(30)"); // Neuen Eintrag in Tabelle person einfügen s.executeUpdate("INSERT INTO person (vorname, nachname)" + "VALUES ('Sarah', 'Schmidt')"); c.close(); Die Derby-Datenbank wird implizit gestartet, wenn eine Verbindung hergestellt wird. Die Datenbank wird im angegebenen Pfad gespeichert. 15