Java: Kapitel 8 Datenbankzugriff mit JDBC Programmentwicklung WS 2008/2009 Holger Röder holger.roeder@informatik.uni-stuttgart.de
Ü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
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
Java Databa Connectivity (JDBC) Seit Java 1.1 existiert mit Java Databa 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
JDBC-Treiber Der jeweilige JDBC-Treiber ist datenbankspezifisch. Für alle relevanten SQL-Datenbanken stehen JDBC-Treiber zur Verfügung. Java- Anwendung gleiche Programmierschnittstelle MySQL JDBC- Treiber Oracle JDBC- Treiber Die pasnde JDBC-Treiberbibliothek muss (typischerwei als.jar-archiv) im Klasnpfad (classpath) vorhanden in. Das Paket java.sql enthält die JDK-Klasn für den JDBC-Zugriff. MySQL-Datenbank Oracle-Datenbank 5
JDBC-Treiber laden Bis einschließlich Java 5 muss vor dem Verbindungsaufbau der zur Datenbank pasnde JDBC-Treiber geladen werden. Dies kann über die Klas Class erfolgen. MySQL: Class.forName("com.mysql.jdbc.Driver"); 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 JDBC- Treibers. Beim ersten Verbindungsaufbau zur Datenbank wird der Treiber automatisch gesucht und geladen. Klasnname muss bekannt in. 6
Verbindungsaufbau zur Datenbank Mit der statischen Methode getconnection() der Klas DriverManager kann eine Verbindung zur Datenbank hergestellt werden: Connection c = DriverManager.getConnection("jdbc:derby:TestDB");... c.clo(); // Verbindung schließen Connection-String Connection-Objekt repräntiert 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", "ur", "password"); Connection-String für Oracle-Datenbank 7
Einfache SQL-Abfragen Abfragen und Änderungen der Datenbank erfolge über Statement- Objekte (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 " + "WHERE vorname = 'Carla'"; SQL-Abfrage ausführen ResultSet result = s.executequery(sql); while (result.next()) { Über Ergebnis iterieren String vorname = result.getstring(1); getxxx(spalte) String nachname = result.getstring(2); liefert entsprechenden int id = result.getint(3); Spaltenwert System.out.format("%s %s (id=%d)%n", vorname, nachname, id); } result.clo(); // Result-Objekt schließen 8
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); String sql2 = "INSERT INTO mitarbeiter (vorname, nachname)" + "VALUES ('Sarah', 'Schmidt')"; int result2 = s.executeupdate(sql2); Änderung durchführen: executeupdate() liefert als Rückgabewert die Zahl der geänderten Zeilen zurück. String sql3 = "UPDATE mitarbeiter " + "SET vorname='sandra' " + "WHERE vorname = 'Sarah' AND nachname = 'Schmidt'"; int result3 = s.executeupdate(sql3);... s.clo(); // Statement schließen c.clo(); // Verbindung schließen 9
Prepared Statements Parametrisierte SQL-Anweisungen werden Prepared Statements 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 ertzt: p.tstring(1, "Emil"); p.tstring(2, "Erler"); Vorteile von Prepared Statements Übersichtlichkeit, Wiederverwendbarkeit, Sicherheit Bequeme Angabe verschiedener Datenformate: tstring(), tint(), tdate(), tblob() etc. Datenbank-Performance txxx(n, wert) tzt konkreten Wert für n-ten Platzhalter p.ttime(3, new Time(Calendar.getInstance().getTimeInMillis())); p.executeupdate(); Platzhalter? 10
Ausnahmebehandlung Tritt im Zusammenhang mit dem Datenbankzugriff ein Fehler auf, wird eine Ausnahme vom Typ SQLException (oder einer Unterklas) geworfen. Typische Auslör 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; die 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
Transaktionen Standardmäßig wird jede einzelne SQL-Anweisung als parate Transaktion angehen 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 =... c.tautocommit(fal); Statement s = c.createstatement(); // Typisches Transaktionsbeispiel: // Banküberweisung von Konto A nach Konto B 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(); Auto-Commit-Modus abschalten Transaktion "committen" (SQL-Anweisungen ausführen) 12
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-Source- Software Apache Derby. Eigenschaften: 100% in Java implementiert Geringer Speicherbedarf (.jar nur ~2 MB) Embedded-Modus, direkte Einbettung in die Java-Applikation http://db.apache.org/derby 13
Einbindung von Java DB in ein Java-Projekt Einbindung der Derby-Bibliothek in ein Java-Projekt in Eclip: 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
Java DB und JDBC System.tProperty("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.clo(); Stammverzeichnis für DB-Dateien tzen Die Derby-Datenbank wird implizit gestartet, wenn eine Verbindung hergestellt wird. Die Datenbank wird im angegebenen Pfad gespeichert. 15