JDBC Pierre Fierz Chapter 9 SQL in Programmiersprachen JDBC Java Database Connectivity JDBC Lecture Datenbanken 24.04.2014 Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen Pierre Fierz Berner Fachhochschule Technik und Informatik 9.1 Contents JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.2 Outline JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.3 SQL in Programmiersprachen JDBC Pierre Fierz • Für grössere Applikationen ist es nötig SQL in einer Programmiersprache einzubetten. • Diese Koppelung wird als Wirtssprachen-Koppelung bezeichnet. • Dabei sind die folgenden Voraussetzungen nötig: • Die Schutzmechanismen der Datenbank müssen auch für SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen ein Programm gelten. • Fremdschlüsselbedingung, Assertion usw. müssen eingehalten werden. • Innerhalb der SQL-Befehle müssen Parameter (Variablen) der Wirtssprache verwendet werden können. • Es muss klar definiert werden, wie die Datentypen der Datenbank in Datentypen der Wirtssprache übersetzt werden. 9.4 SQL in Programmiersprachen (2) JDBC Pierre Fierz SQL in Programmiersprachen • Es gibt mehere Möglichkeiten SQL in einer Programmiersprache einzubinden. • Wir werden hier die Java Datenbankanbindung JDBC anschauen. Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Eine weitere Möglichkeit ist embedded SQL, das für beliebige Sprachen standardisiert ist. • Ferner existieren auch objektrelationale Systeme wie Java Persitence API (JPA). 9.5 Outline JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.6 Was ist JDBC JDBC Pierre Fierz • JDBC = Java DataBase Connectivity ist mit ODBC (Open Database Connectivity) von Microsoft vergleichbar. • JDBC ist ein low-level oder call-level API um • • • • Die Verbindung zu einer Datenbank herzustellen SQL-Befehle abzusetzen Resultate zu analysieren und zu verarbeiten Information über die Datenbank bereitzustellen. SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • JDBC ermöglicht einen produktunabhängigen Datenbankzugriff. • JDBC ist eine Basis für high-level API’s, die das Arbeiten mit SQL vollständig verstecken und z.B. direkt Java-Objekte verwalten. 9.7 JDBC JDBC Package-Struktur Pierre Fierz • JDBC besitzt die folgende Package-Struktur SQL in Programmiersprachen JDBC Package Java Database Connectivity JDBC UserPackage <<implements>> <<uses>> java.sql VendorPackage Programmieren mit JDBC SQL-ROUTINEN und JDBC • java.sql: Dieses Package gehört ab Java 1.1 zum Meta-Informationen Standard API. • VendorPackage: Dieses Package enthält für jedes Interface von java.sql eine entsprechende Implementationsklasse. • Es stellt die eigentliche Funktionalität zur Verfügung und wird von Datenbank- oder Drittherstellern vertrieben. • UserPackage: Dieses Package erzeugt und benützt Variablen der verschiedenen Interfaces von java.sql. 9.8 JDBC Das Package java.sql Pierre Fierz • Nachfolgend sind die wichtigsten Interfaces und Klassen des Packages java.sql dargestellt. SQL in Programmiersprachen Java Database Connectivity JDBC java.sql <<interface>> ResultSet <<interface>> <<creates>> Statement <<class>> <<interface>> DriverManager Driver <<creates>> Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen <<creates>> <<creates>> <<interface>> <<interface>> ResultSetMetaData PreparedStatement <<interface>> <<interface>> Connection <<creates>> <<creates>> DatabaseMetaData <<interface>> CallableStatement <<creates>> 9.9 Das Package java.sql (2) JDBC Pierre Fierz SQL in Programmiersprachen • Damit der Java-Code unabhängig von der verwendeten Datenbank ist gelten für die Erzeugung von Objekten die folgenden Regeln: • Objekte von Implementationsklassen im VendorPackage Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen werden niemals direkt mit new erzeugt. • Dazu existieren Get- oder Create-Methoden • Die Namen der Implementationsklassen bleiben dem Anwender Package verborgen. • Einzige Ausnahme ist der Name der Driverklasse. 9.10 Driver Interface JDBC Pierre Fierz • Die Aufgabe des Drivers ist, eine Verbindung zwischen dem Java-Programm und der Datenbank herzustellen. • Eine Driverimplementation muss eine “static section” enthalten, die die folgenden Aufgaben übernimmt: 1 2 Kreieren einer Instanz des Drivers Registrieren des Drivers beim Drivermanager SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Die gewünschten Drivers können mit der Methode Class.forname geladen werden (der Driver muss im Classpath sein). • Ab JDBC Version 4.0 muss der Driver nicht mehr explizit geladen werden • Die Klasse Drivermanager ist in der Lage den Driver zu finden und zu laden. 9.11 DriverManager Klasse • Diese Klasse enthält nur statische Methoden. • Für den Anwender ist die Methode getConnection, die die Verbindung mit der Datenbank aufnimmt am wichtigsten. • Der Methode muss eine sogennante JDBC URL übergeben werden. • An Hand dieser URL weiss der Drivermanager welche Datenbank geöffnet werden muss. • Die JDBC URL hat das folgende Format: jdbc:<subprotocol>:<subname> • <subprotocol> – ist der offizielle Name eines Drivers. Subprotokolle können von Driver Herstellern bei Javasoft registriert werden. • <subname> – dient dazu, die Datenbank zu identifizieren. Der genaue Aufbau dieses Teiles ist Herstellerabhängig. JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen Verbindung zu einer Datenbank aufnehmen Connection con = DriverManager.getConnection( "jdbc:mysql://db.bfh.ch/fierzdb" Name, Passwort) 9.12 Statement und Resultset Interface JDBC Pierre Fierz • Mit Hilfe eines Connection Objekts können Statement Objekte kreiert werden. • Statement dienen dazu, SQL-Befehle der Datenbank zu senden. • Die drei folgenden Methoden sind besonders wichtig: 1 2 3 executeQuery: für SELECT executeUpdate: für INSERT, UPDATE, DELETE, CREATE, DROP usw. execute: für SQL-Befehle, die mehr als ein Resultat liefern (stored Procedures); SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Die Methode executeQuery gibt ein Objekt des Typs Resultset zurück. • Ein Resultset ist die Implementation einer Relation • Die Methode next iteriert durch alle Tupel der Relation hindurch. • Mit den Methoden get<Datatype> kann der Wert der einzelnen Attribute ermittelt werden. 9.13 Metainformationen JDBC Pierre Fierz • Mit dem Interface DatabaseMetadata können Informationen über das Datenbankschema geholt werden • • • • Tabellen Attribute Schlüssel usw. • Mit dem Interface ResultSetMetaData können Informationen über ein Objekt des Typs ResultSet gewonnen werden. SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Dies wird benutzt, wenn das Resultat eines Queries zur Kompilationszeit nicht bekannt ist. • Folgende Informationen sind verfügbar: • Anzahl Attribute • Name der Attribute • Tabelle der Attribute • Datentyp • usw. 9.14 Metainformationen (2) JDBC Pierre Fierz • Die Klasse DriverPropertyInfo dient dazu, Informationen über einen bestimmten Driver zu erhalten. • Zum Beispiel kann man so erfahren, welche Parameter beim Öffnen der Datenbank (connect) notwendig sind (user, password usw.). • Es ist auch möglich bein Aufbau der Connection gewisse Einstellungen des Drivers zu verändern. • Bevor die Informationen zur Verfügung stehen, muss der SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen Driver geladen werden. Hohlen der Driver Properties try { /* Laden des Drivers ab JDBC 4.0 nicht mehr noetig */ Class.forName("com.mysql.jdbc.Driver"); /* Driver hohlen */ Driver dv = DriverManager.getDriver("jdbc:mysql://a/b"); /* Hohlen der Driverproperties */ return dv.getPropertyInfo(url, po); } catch (SQLException e) { ; } 9.15 Weitere Klassen JDBC Pierre Fierz SQL in Programmiersprachen • Neben den Klassen und Interfaces in der Abbildung existieren noch die folgenden Klassen im Package java.sql • Klassen für das Exceptionhandling • SQLException und Subklassen • SQLWarning • DataTruncation Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Date, Time, TimeStamp: Diese Klassen garantieren die Kompatibilität zwischen Datenbank und Java bezüglich Zeit und Datum. • Types: Diese Klasse enthält Konstanten, welche die generischen SQL-Typen definieren 9.16 Outline JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.17 JDBC Beispiele JDBC Pierre Fierz • Das nächste Beispiel zeigt der Aufbau der Verbindung zur Datenbank • Das JDBC Vendopackage muss im Classpath vorhanden sein. Verbindung zur Datenbank aufnehmen SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Connection con = null; Meta-Informationen // Verbindung mit der Datenbank aufnehmen. Mit Hilfe // des Subprotokolls "mysql" wird der // Drivermanager wissen, dass die Verbindung zu einer // Mysql-Datenbank aufgenommen werden muss. // // Bei Mysql ist die Angabe von User und Passwort // notwendig. try { con = DriverManager.getConnection( "jdbc:mysql://db.bfh.ch/fierzdb", user, passwd ); } catch (SQLException e) { // Verbindung kann nicht aufgenommen werden. System.exit(1); } 9.18 JDBC Beispiele (2) JDBC Pierre Fierz • Das nächste Beispiel zeigt ein einfaches Select Beispiel. Absetzen eines Select Statements // Beispiel SELECT Befehl try { Statement stmt = con.createStatement(); // Aufbauen eines Queries ResultSet rs = stmt.executeQuery( "SELECT mNr, Name, Ort, Plz " + "FROM Mitarbeiter"); while (rs.next()) { System.out.print(rs.getInt(1) + " / " + rs.getString(2) + " / "); // Es ist auch möglich mit dem Namen des Feldes // auf die Daten zuzugreifen. System.out.println(rs.getString("Ort") + " " + rs.getString("Plz")); } // Statement explizit schliessen, damit die // Datenbankresourcen sofort freigegeben werden und // nicht erst bei einer Garbagecollection. stmt.close(); } catch (Exception e) { System.out.println(e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.19 JDBC Beispiele (3) JDBC Pierre Fierz • Das nächste Beispiel zeigt einen Insert Befehl Ausführen eines Inserts // UPDATE Befehle try { Statement stmt = con.createStatement(); SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen // Absetzen eines Inserts. Dazu muss die Methode // executeUpdate verwendet werden. int changes = stmt.executeUpdate( "INSERT INTO Projekt (pNr, PName, aNr, Standort) " + "VALUES (101, ’Neues Projekt’, 3, ’Bern’)"); stmt.close(); } catch (Exception e) { System.out.println(e); } 9.20 JDBC Beispiele (4) JDBC Pierre Fierz • Wenn der Benutzer die entsprechenden Rechte besitzt, können auch DDL Befehle ausgeführt werden. Kreieren einer Tabelle // Kreieren einer neuen Tabelle try { Statement stmt = con.createStatement(); SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen stmt.executeUpdate("CREATE TABLE kunde (" + "kNr INTEGER NOT NULL, " + "KName VARCHAR(30) NOT NULL, " + "Ort VARCHAR(30) NOT NULL," + "PRIMARY KEY (kNr))"); stmt.close(); } catch (Exception e) { System.out.println(e); } 9.21 JDBC Beispiele (5) JDBC Pierre Fierz • Prepared Statements dienen dazu, oft verwendete Befehle zu beschleunigen und gleichzeitig die Parameterübergabe zu vereinfachen Insert mit einem prepared Statement // Prepared Statements mit Parameteruebergabe. // erlaubt es ein SQL-Befehl mehrmals zu verwenden. try { PreparedStatement stmt = con.prepareStatement( "INSERT INTO Projekt " + "(pNr, PName, paNr, PStandort) VALUES (?,?,?,?)"); // Parameter uebergeben stmt.setInt(1, 25); stmt.setString(2, "Coop Baustelle"); stmt.setInt(3, 4); stmt.setString(4, "Belp"); // Befehl ausfuehren int changes = stmt.executeUpdate(); stmt.close(); } catch (Exception e) { System.out.println(e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.22 JDBC Beispiele (6) • Um herauszufinden ob ein Attribut einen Nullwert enthält, muss zuerst das entsprechende Attribut mit der Methode get<Datatyp> gelesen werden. • Anschliessend kann mit der Klassenmethode ResultSet.wasNull() gefragt werden, ob das Resultat ein Nullwert ist. Behandlung von NULL Werten // Behandlung von Nullvalues try { Statement stmt = con.createStatement(); JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen // Aufbauen eines Queries ResultSet rs = stmt.executeQuery( "SELECT mNr, Name, Vorgesetzter " + "FROM Mitarbeiter"); while (rs.next()) { int vorgesetzter = rs.getInt(3); if (rs.wasNull() == true) System.out.println("Mitarbeiter " + rs.getInt(1) + ". " + rs.getString(2) + " hat keinen Vorgesetzten"); } stmt.close(); } catch (Exception e) { System.out.println(e); } 9.23 JDBC Beispiele (7) • In einem Resultset kann man auch Rückwärtsscrollen und JDBC Pierre Fierz den Cursor absolut oder relativ positionieren. Scrollen im Resultset // Beispiel Scroll im Resultset try { Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); // Aufbauen eines Queries ResultSet rs = stmt.executeQuery( "SELECT * FROM Mitarbeiter " + "ORDER BY mNr"); // Lieferanten in der Umgekehrten Reihenfolge Ausgeben rs.afterLast(); while (rs.previous()) { System.out.print(rs.getString("name")); } // Auf 7. Tupel positionieren if(rs.absolute(7)) { // Nun 5 Tupel rückwaerts rs.relative(-5); } stmt.close(); } catch (Exception e) { System.out.println(e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.24 JDBC Beispiele (8) JDBC Pierre Fierz • Man kann Tupel in einem Resultset auch verändern und in der DB zurückspeichern. Update von Tupel im Resultset // Beispiel Update im Resultset try { Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen // Aufbauen eines Queries ResultSet rs = stmt.executeQuery( "SELECT * FROM Mitarbeiter " + "ORDER BY mNr"); // Setzen auf tupel sieben und Ort aendern if (rs.absolute(7)) { rs.updateString("Ort", "Genf"); rs.updateRow(); } stmt.close(); } catch (Exception e) { System.out.println(e); } 9.25 JDBC Beispiele (9) • Im nächsten Beispiel wird ein neues Tupel in die Datenbank eingefügt. Insert von Tupel im Resultset // Beispiel Update und Insert im Resultset try { Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); // Aufbauen eines Queries ResultSet rs = stmt.executeQuery("SELECT * FROM Projekt " + "ORDER BY pNr"); // Einfuegen eines Projektes rs.moveToInsertRow(); // Daten abfuellen rs.updateInt("pNr", 102); rs.updateString("PName", "Coop Baustelle"); rs.updateInt("paNr", 2); rs.updateString("Standort", "Belp"); // Lieferant zurueckschreiben rs.insertRow(); // Auf Urspruengliche Position zurueck rs.moveToCurrentRow(); stmt.close(); } catch (Exception e) { System.out.println(e); } JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.26 Outline JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.27 Aufruf von Prozeduren und Funktionen • Die Syntax für den Aufruf einer Prozedur hat die folgende Form: SQL Syntax (JDBC call) <jdbc-call> ::= {CALL <procname> ([<arg> [, <arg>]. . . ])} <arg> ::= {? | <literal>} JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Aufruf einer Prozedur mit ouput Parameter Meta-Informationen try { // Aufrufen der Prozedur "Stundenproc" CallableStatement cstmt = con.prepareCall( "{CALL Stundenproc(?, ?)}"); // Parameter nummer 1 setzen (Projektnummer) cstmt.setInt(1,2); // Rueckgabeparameter (Parameter 2) registrieren cstmt.registerOutParameter(2, Types.FLOAT); // Ausfuehren der Funktion cstmt.execute(); // Lesen und ausgeben des Resultats System.out.println(cstmt.getFloat(2)); } catch (Exception e) { System.out.println("*** " +e); } 9.28 Aufruf von Prozeduren und Funktionen (2) • Die Syntax für den Aufruf einer Funktion hat die folgende Form: SQL Syntax (JDBC call) <jdbc-funcall> ::= {? = CALL <procname> ([<arg> [, <arg>]. . . ])} <arg> ::= {? | <literal>} JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Aufruf einer Funktion Meta-Informationen try { // Aufrufen der Funktion "Stundenfunc" CallableStatement cstmt = con.prepareCall( "{? = CALL Stundenfunc(?)}"); // Parameter nummer 2 setzen (ProjektNummer) cstmt.setInt(2,2); // Rueckgabewert (Parameter 1) registrieren cstmt.registerOutParameter(1, Types.FLOAT); // Ausfuehren der Funktion cstmt.execute(); // Lesen und ausgeben des Resultats System.out.println(cstmt.getInt(1)); } catch (Exception e) { System.out.println("*** " +e); } 9.29 Prozeduren und Resultsets JDBC Pierre Fierz • Prozeduren können auch Resultsets zurückgeben. • Dazu genügt es in der Prozedur ein normales Select Statement zu schreiben. Prozedur mit Resultset SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen CREATE PROCEDURE AnzProj() BEGIN SELECT a.aNr, a.AName, COUNT(*) FROM Abteilung a JOIN Projekt p ON a.aNr = p.paNr GROUP BY a.aNr, p.AName; END 9.30 Prozeduren und Resultsets (2) JDBC Pierre Fierz • Die Prozedur kann nun in einem Programm aufgerufen werden. • Anschliessend kann der Resultset abgearbeitet werden. Aufruf einer Prozedur mit Resultset try { // Aufrufen der Funktion "AnzProj" CallableStatement cstmt = con.prepareCall("{call AnzProj()}"); // Ausfuehren der Funktion if (cstmt.execute()) { // ResultSet hohlen und lesen ResultSet rs = cstmt.getResultSet(); while (rs.next()) { System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3)); } } } catch (Exception e) { System.out.println("*** " +e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.31 Prozeduren und Resultsets (3) JDBC Pierre Fierz • In manchen DBMS (darunter auch Mysql) ist es möglich, dass eine Routine mehrere ResultSets zurückgibt. • Die Anzahl Resultset ist gleich der Anzahl Select Statements in der Prozedur. Prozedur mit zwei Resultsets CREATE PROCEDURE AnzProj1() BEGIN -- Erstes ResultSet SELECT a.aNr, a.AName, COUNT(*) FROM Abteilung a JOIN Projekt p ON a.aNr = p.paNr GROUP BY a.aNr, p.AName; SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen -- Zweites ResultSet SELECT a.aNr, a.AName, 0 FROM Abteilung a WHERE NOT EXISTS (SELECT * FROM Projekt p WHERE a.aNr = p.paNr); END 9.32 Prozeduren und Resultsets (4) JDBC Pierre Fierz • Das nächste Programmfragment ruft die Prozedur auf und listet anschliessend beide Resultate aus. Aufruf einer Prozedur mit mehreren Resultsets try { // Aufrufen der Funktion "AnzProj1" CallableStatement cstmt = con.prepareCall( "{call AnzProj1()}"); // Ausfuehren der Funktion if (cstmt.execute()) { do { // ResultSet hohlen und lesen ResultSet rs = cstmt.getResultSet(); while (rs.next()) { System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getInt(3)); } } while(cstmt.getMoreResults()); } } catch (Exception e) { System.out.println("*** " +e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.33 Outline JDBC Pierre Fierz 1 SQL in Programmiersprachen 2 Java Database Connectivity JDBC SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 3 Programmieren mit JDBC 4 SQL-ROUTINEN und JDBC 5 Meta-Informationen 9.34 Metainformationen JDBC Pierre Fierz SQL in Programmiersprachen • Es gibt bei der Programmierung Probleme, die nicht mit den bisherigen Methoden gelöst werden können. • Insbesondere sind bei generischen Programmen die SQL Befehle zur Kompilationszeit nicht bekannt. Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen • Mit der Klasse ResultsetMetaData kann zur Laufzeit der Aufbau eines Resultsets bestimmt werden. • Mit der Klasse DatabaseMetaData können beliebige Informationen über das Datenbankschema gewonnen werden. 9.35 ResultSetMetaData JDBC Pierre Fierz • Das nächste Beispiel zeigt, wie ein Resultset analysiert werden kann. Scrollen im Resultset // Beispiel fuer die Benutzung von ResultSetMetaData try { Statement stmt = con.createStatement(); // Aufbauen eines Queries ResultSet rs = stmt.executeQuery( "SELECT * FROM Mitarbeiter m natural join MitProj mp " + " natural join Projekt"); // Metadaten hohlen ResultSetMetaData rsm = rs.getMetaData(); // Anzahl Kolonnen bestimmen int cols = rsm.getColumnCount(); while (rs.next()) { // Name, Datentyp und Inhalt der einzelnen Kolonnen // abfragen und ausgeben for (int i = 1; i <= cols; i++) { String cna = rsm.getColumnName(i), cco = rs.getString(i); int cty = rsm.getColumnType(i); System.out.println(cna + " (" + cty + "): " + cco); } } stmt.close(); } catch (Exception e) { System.out.println(e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.36 DatabaseMetaData • Das nächste Beispiel zeigt, wie Informationen über die einzelnen Relationenschematas der Datenbank gewonnen werden kann. Scrollen im Resultset JDBC Pierre Fierz SQL in Programmiersprachen Java Database Connectivity JDBC // Beispiel fuer die Benutzung von DatabaseMetaData try { DatabaseMetaData dbmd = con.getMetaData(); // Information ueber alle Tabellen String [] s = {"TABLE"}; ResultSet rs1 = dbmd.getTables("firma", null, "%", s); Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen while (rs1.next()) { String tn = rs1.getString("TABLE_NAME"); // Einlesen aller Attribute der Tabelle ResultSet rs2 = dbmd.getColumns("firma", null, tn, null); while (rs2.next()) { // Ausgeben einiger Informationen System.out.println(rs2.getString("COLUMN_NAME") + " / " + rs2.getString("TYPE_NAME") + "(" + rs2.getInt("COLUMN_SIZE") + ")"); } } } catch (Exception e) { System.out.println(e); } 9.37 Die execute Methode JDBC Pierre Fierz SQL in Programmiersprachen • Bei generischen Programmen weiss man oft nicht, ob ein SQL Befehl ein Query oder ein Update ist. • In diesem Fall wird man die execute Methode benutzen • Ist der Rückgabewert true, so war der Befehl ein Query Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen und der Resultset kann mit der Methode getResulSet() bestimmt werden. • Ist der Rückgabewert false, so war der Befehl kein Query. In diesem Fall kann mit der Methode getUpdateCount() die Anzahl veränderter Tupel ermittelt werden. 9.38 Die execute Methode (2) JDBC Pierre Fierz • Im folgenden Beispiel kann ein beliebiges SQL Statement auf der Commando Zeile eingegeben werden. Scrollen im Resultset // Beispiel fuer die Benutzung von execute und // ResultSetMetaData try { Statement stmt = con.createStatement(); // SQL-Statement ist im 4. Argument der Kommandozeile: // Ausfuehren des Statements if (stmt.execute(args[3])) { // Das Statement ist ein Query wir muessen also // die Resultset und die Metadaten hohlen ResultSet rs = stmt.getResultSet(); ResultSetMetaData rsm = rs.getMetaData(); // Weitere Verarbeitung // ... } else { // Kein Query anzahl veraenderter Tuple herausgeben System.out.println("Update Count: " + stmt.getUpdateCount()); } stmt.close(); } catch (SQLException e) { System.out.println(e); } SQL in Programmiersprachen Java Database Connectivity JDBC Programmieren mit JDBC SQL-ROUTINEN und JDBC Meta-Informationen 9.39