JDBC (Stichworte) Udo Kelter 19.12.2011 Zusammenfassung dieses Lehrmoduls JDBC (Java Database Connectivity) ist eine Schnittstelle, über die von Java-Programmen aus auf die Inhalte relationaler Datenbanken zugegriffen werden kann. Dieses Lehrmodul stellt die wichtigsten Funktionen vor. Insb. wird die Frage beantwortet, wie mit einer typsicheren Sprache wie Java die Ergebnisse von Abfragen, deren Typ man nicht statisch bestimmen kann, verarbeitet werden können. Vorausgesetzte Lehrmodule: obligatorisch: - Einführung in SQL Stoffumfang in Vorlesungsdoppelstunden: 1 1.0 JDBC (Stichworte) 2 Inhaltsverzeichnis 1 Motivation 1.1 JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 2 Aufbau einer Verbindung zum Datenbankserver 2.1 JDBC-Treiber laden . . . . . . . . . . . . . . . . . . . . . . . 2.2 Connection-Objekt erzeugen . . . . . . . . . . . . . . . . . . . 4 4 4 3 SQL-Statements 3.1 SQL-Statement-Objekte erzeugen . . . . . . . . . . . . . . . . 3.2 executeUpdate . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 executeQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 5 6 4 ResultSets als Abfrageergebnisse 4.1 ResultSet als lineare Liste . . . . . . 4.2 Positionierbare ResultSets . . . . . . 4.3 Auslesen eines Tupels . . . . . . . . 4.4 Automatisch aktualisierte ResultSets . . . . 6 6 6 6 7 5 Änderbare ResultSets 5.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Ändern eines Tupels . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 6 Vorübersetzte Statements 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Fehlerbehandlung 10 Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 10 c 2011 Udo Kelter Stand: 19.12.2011 Dieser Text darf für nichtkommerzielle Nutzungen als Ganzes und unverändert in elektronischer oder gedruckter Form beliebig weitergegeben werden und in WWW-Seiten, CDs und Datenbanken aufgenommen werden. Jede andere Nutzung, insb. die Veränderung und Überführung in andere Formate, bedarf der expliziten Genehmigung. Die jeweils aktuellste Version ist über http://kltr.de erreichbar. JDBC (Stichworte) 1 3 Motivation praktisches Problem: Zugriff auf eine relationale Datenbank von einem Programm aus; Detailprobleme: - Aufbau und Überwachung einer Verbindung zum Datenbankserver - Konversion von Daten in der Datenbank und in den Laufzeitobjekten der jeweiligen Programmiersprache speziell bei Abfragen: Darstellung einer (Ergebnis-) Relation als Laufzeit-Datenstruktur - Gestaltung geeigneter und leicht bedienbarer APIs Fehlerbehandlung 1.1 JDBC JDBC (Java Database Connectivity) ... - “is the industry standard for database-independent connectivity between the Java programming language and a wide range of SQL databases and other tabular data sources, such as spreadsheets or flat files. - The JDBC API provides a call-level API for SQL-based database access. (von: ) http://www.oracle.com/technetwork/java/javase/jdbc/index.html → jeder Hersteller eines relationalen DBMS kann/sollte eine Implementierung des JDBC APIs mitliefern wird Treiber (driver) genannt (Analogie zum Anschluß von Plattenlaufwerken) → ggf. in der Doku danach suchen c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 2 2.1 4 Aufbau einer Verbindung zum Datenbankserver JDBC-Treiber laden Treiber wird identifiziert durch Paket- und Klassennamen, Beispiel: org.postgresql.Driver Laden: Class.forName(driver class); Beispiel: Class.forName("org.postgresql.Driver"); 2.2 Connection-Objekt erzeugen Verbindungen werden durch Connection-Objekte repräsentiert. Deklaration: Connection con = null; Aufbau der Verbindung: con = DriverManager.getConnection(db, user, passw); Parameter von getConnection: db Angabe der Datenbank in folgender Syntax: protokoll://rechnername/dateipfad Beispiel: jdbc:postgresql://pi81.informatik.uni-siegen.de/dbs1 user Benutzername passw Passwort 3 3.1 SQL-Statements SQL-Statement-Objekte erzeugen Anweisungen werden durch Statement-Objekte repräsentiert. Deklaration: c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 5 Statement stmt; mehrere Schritte trennen: 1. Statement-Objekt erzeugen und initialisieren 2. die enthaltene Anweisung eintragen 3. Anweisung ausführen (ggf. mehrfach) Statement-Objekt initialisieren: stmt = con.createStatement(); im Zustand des Statement-Objekts ist vermerkt, zu welcher Verbindung es gehört! einfachste Formen, um Anweisungen aufzubauen und gleich auszuführen: ResultSet result = stmt.executeQuery("SELECT..."); int num = stmt.executeUpdate("INSERT ..."); 3.2 executeUpdate allgemeines Kommando für alle SQL-Kommandos, die eine Datenbank ändern (insb. create table, insert, delete, ...): int executeUpdate(String sql) Beispiel: int num = stmt.executeUpdate("INSERT ..."); Zurückgegebener Wert: - Zahl der eingefügten / gelöschten / geänderten Tupel 0 bei create table und u.ä. Kommandos c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 3.3 6 executeQuery eigenes Kommando für Abfragen: ResultSet executeQuery(String sql) Beispiel: ResultSet result = stmt.executeQuery("SELECT..."); 4 4.1 ResultSets als Abfrageergebnisse ResultSet als lineare Liste einfachste Form der Erzeugung eines ResultSets: ResultSet result = stmt.executeQuery("SELECT..."); erzeugt eine lineare Liste von Tupeln (rows) durchlaufen (max. 1*) mit Operation next: while(result.next()) { verarbeite aktuelles Tupel } 4.2 Positionierbare ResultSets statt als lineare Liste können ResultSets als beliebig positionierbare (“scrollbare”) Kollektion erzeugt werden; hierzu: stmt = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE); result = stmt.executeQuery("SELECT..."); Positionierungsoperationen (next, previous, first, last, relative, absolute) s. JDBC-Tutorial, Abschnitt “Cursors”. 4.3 ... Auslesen eines Tupels Problem: Typ der Ergebnisrelation ist i.a. statisch (zur Übersetzungszeit) nicht bekannt – Java ist aber eine typsichere Sprache c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 7 Lösung: die Operationen getInt, getString usw. - - i.a. getXXX, worin XXX ein Typname ist liefern einen Wert vom Typ XXX zurück → : Entwickler muß den Typ des Attributs kennen Vorsicht: teilweise implizite Konversionen! beziehen sich auf das aktuelle Tupel jeweils zwei Varianten, die das gewünschte Attribut verschieden identifizieren: - getXXX(string): anhand des Namens getXXX(int): anhand der Position (1,...) Beispiele: name = result.getString("Vorname"); plz = result.getInt(5); ca. 15 weitere s. http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html 4.4 Automatisch aktualisierte ResultSets Problem: ein ResultSets ist eine Kopie der selektierten Daten zum Zeitpunkt seiner Erstellung. – Originaldaten können sich während der Existenz des ResultSets ändern. Wunsch: der ResultSets soll automatisch an solche Änderungen angepaßt werden Lösung: “sensitive” ResultSets stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE); result = stmt.executeQuery("SELECT..."); c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 5 8 Änderbare ResultSets 5.1 Motivation Problem: oft will man einen ResultSets durchlaufen und jedes Tupel sofort verändern. Beispiel: erhöhe alle Preise eines Warenbestands um 5%. Lösung 1: jedesmal ein update-Kommando - sehr umständlich und ineffizient bessere Lösung 2: Änderbare ResultSets1 hierzu: concurrency level UPDATABLE: stmt = con.createStatement( ResultSet.CONCUR_UPDATABLE); result = stmt.executeQuery("SELECT..."); (Vorgabewert für den concurrency level: READ ONLY) 5.2 Ändern eines Tupels i.w. analog zu den getXXX-Operationen: Operationen updateInt, updateString, usw. - beziehen sich auf das aktuelle Tupel heißen i.a. updateXXX, worin XXX ein Typname ist 1. Parameter: Name oder Nummer des gewünschten Attributs 2. Parameter: neuer Wert des Attributs Vorsicht: Konversionen! Rückgabewert void Beispiele: 1 nach einer Änderung ist der Begriff ResultSet eigentlich nicht mehr korrekt. c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 9 result.updateString("Vorname", "Hans"); result.updateInt(5,57076); ca. 15 weitere s. http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html 6 Vorübersetzte Statements Problem: Übersetzen eines textuellen SQL-Kommandos ist relativ aufwendig (Syntax, Prüfung aller Bezeichner, ...); Aufwand vermeidbar, wenn immer wieder fast gleiche SQL-Kommandos ausgeführt werden. Lösung: Prepared Statements. Beispiel: String insertcmd = "INSERT INTO lieferungen " + "(Kundennummer, Lieferadresse, Betrag, Datum) " + "VALUES ( ?, ?, 25, 31.12.2011 )" PreparedStatement psInsertLfg; psInsertLfg = con.prepareStatement(insertcmd); Vorübersetzen mit prepareStatement: - SQL-String: “may contain one or more ’ ?’ IN parameters” findet schon hier Syntaxfehler Nachliefern der Parameter mit setXXX-Kommandos: psInsertLfg.setInt (1, 181917); psInsertLfg.setString (2, "Schulte, Maria"); 1. Parameter: Nr. des offenen Parameters 2. Parameter: Wert gem. Wertebereich XXX Ausführen des Kommandos nach Füllen aller Parameter: psInsertLfg.executeUpdate(); weitere Details s. http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html c 2011 Udo Kelter Stand: 19.12.2011 JDBC (Stichworte) 7 10 Fehlerbehandlung Alle Datenbankzugriffe müssen in try/catch-Blöcken gekapselt werden. Zugriffsoperationen werfen exceptions vom Typ SQLException. Details s. http://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception Operationen auf SQLException: getMessage liefert eine verbale Beschreibung des Fehlers getSQLState() liefert einen Fehlercode gemäß ANSI-92-Standard getErrorCode() liefert einen herstellerspezifischen Fehler-Code i.a. können mehrere SQLExceptions bei einen Datenbankzugriff auftreten, ferner mehrere Warnungen Auslesen der Liste der SQLExceptions bzw. Warnungen s. http://docs.oracle.com/javase/tutorial/jdbc/basics/sqlexception.html Literatur [SQL] Kelter, U.: Lehrmodul “Einführung in SQL”; 2005 c 2011 Udo Kelter Stand: 19.12.2011