Grundlagen von Datenbanken SS 2010 Kapitel 8: Datenbank-Einbettung in Programmiersprachen Prof. Dr. Stefan Böttcher Universität Paderborn Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 1 Java Database Connectivity (JDBC) • Paket von Java-Klassen zum DB-Zugriff mit SQL • vom Ziel-DBMS unabhängige API • Standard seit Java 1.1 Java-Programm JDBC: API Treibermanager Treiber Zieldatenbanksystem Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 2 Java-Interfaces von JDBC • • • • • SQLDriver : Treiber für ein Ziel-DBMS oder ODBC SQLDriverManager : registriert Treiber Connection : Für Verbindungen Statement : für Statement-Objekt, z.B. Query ResultSet : für Ergebnismenge Die Klassen zu diesen Interfaces werden von DB-Herstellern implementiert JDBC-ODBC-Brücke wird von SUN mitgeliefert Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 3 Access - Datenbank anschließen unter ODBC 2. ODBCName hinzufügen 1. DB da 3. OK wählen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 4 MySQL- Datenbank anschließen unter ODBC 1. DB da 3. Server, User, Passwort eingeben und danach DB auswählen 2. ODBCName hinzufügen 4. OK wählen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 5 Datenbank anschließen unter ODBC ODBC, Excel/Access und 64-Bit Betriebssysteme (z.B. Windows 7, Windows Vista) • 64-Bit ODBC-Treiber für Access und Excel werden erst mit Office 2010 geliefert Workaround • 32-Bit ODBC-Datenquellen-Administrator aufrufen c:\windows\SysWOW64\odbcad32.exe • 32-Bit Java-Version verwenden Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 6 Datenbankzugriffe mit JDBC • Treiber laden Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); • Verbindung herstellen con = DriverManager.getConnection("jdbc:odbc:odbc2access"); • Statement-Objekte definieren Statement stmt = con.createStatement() ; • Datenbank zugreifen, z.B. einfügen stmt.executeUpdate(“ insert into Liefert values(‘IBM‘, ‘pc500‘, 2500,6) “); • Statement und Verbindung zum DBMS schließen stmt.close( ) ; con.close( ) ; Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 7 Datenbank-Anfragen mit JDBC Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:odbc2access"); Statement stmt = con.createStatement() ; Datenbankanfrage stellen ResultSet rsLiefert = stmt.executeQuery( “ select * from Liefert where Teil = ‘pc500‘ “); while ( rsLiefert.next( ) ) // hole nächstes Tupel aus Result-Set { ausgabe += rsLiefert.getString( "Lieferant" ) ; // ggf. weitere Spalten ausgeben } stmt.close( ) ; con.close( ) ; Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 8 Datenbank anlegen mit JDBC-Programm import java.sql.*; public class dbinit { public static void main( String[] args ) { String ergebnis = "" ; try { Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Treiber für ODBC Connection con = DriverManager.getConnection("jdbc:odbc:odbc2access"); try { ergebnis = makeDB( con ) ; // : :DB-Name unter ODBC System.out.println( ergebnis ) ; } finally { con.close( ) ; } } catch (Exception e) { System.out.println( e ) ; } } // main zuende public static String makeDB( Connection con ) { String ausgabe="" ; // String zum Sammeln der Ausgabe try { Statement stmt = con.createStatement() ; stmt.executeUpdate( "create table Liefert( Lieferant char(10), Teil char(10), Preis int, Lieferzeit int ) " ); stmt.executeUpdate( "Insert into Liefert values('Vobis ','pc400',1700,3)" ); stmt.close( ); // Statement schließen ausgabe += "\nDatenbank initialisiert.\n" ; } catch (Exception e) { ausgabe += "\n" + "Fehler: " + e ; } return ausgabe ; } // makeDB zuende } // class dbinit zuende Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 9 Datenbank lesen mit JDBC-Programm (1) import java.sql.*; public class dbselect { public static void main( String[] args ) { String ergebnis = "" ; try { Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Treiber für ODBC Connection con = DriverManager.getConnection("jdbc:odbc:odbc2access"); try { ergebnis = selectTab( con, "2200" ) ; // : :DB-Name unter ODBC System.out.println( ergebnis ) ; } finally { con.close( ) ; } } catch (Exception e) { System.out.println( e ) ; } } // main zuende // es folgt noch : public static String selectTab( Connection con, String limit ) { // berechne die richtige Ausgabe siehe nächste Folie } // Funktion selectTab zuende } // class dbselect zuende Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 10 Datenbank lesen mit JDBC-Programm (2) import java.sql.*; public class dbselect { public static void main( String[] args ) { … } public static String selectTab( Connection con, String limit ) { String ausgabe="" ; // String zum Sammeln der Ausgabe try { Statement stmt = con.createStatement() ; ResultSet rsLiefert = stmt.executeQuery( "SELECT * FROM Liefert WHERE Preis < " + limit ) ; // Strings in SQL müssten zusätzlich in einfache Hochkommas: // "SELECT * FROM Liefert WHERE Teil = '" + limit + "'" ) ; ausgabe += "\n\nLiefert:\n( Lieferant Teil Preis Lieferzeit )" ; while (rsLiefert.next()) // hole nächstes Tupel aus Result-Set { ausgabe += "\n" + rsLiefert.getString("Lieferant") + " " + rsLiefert.getString("Teil") + " " + rsLiefert.getInt("Preis") + " " + rsLiefert.getInt("Lieferzeit") ; } rsLiefert.close() ; stmt.close() ; // ResultSet schließen , Statement schließen } catch (Exception e) { ausgabe += "\nFehler bei Anfrage an die Datenbank:\n" + e ; } return ausgabe ; } // Funktion selectTab zuende } // class dbselect zuende Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 11 Datenbankschema lesen import java.sql.*; public class dbinf { public static void main( String[] args ) { String ergebnis = "" ; try { Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Connection con = DriverManager.getConnection("jdbc:odbc:odbc2access"); ergebnis = accessDB( con ) ; System.out.println( ergebnis ) ; } catch (Exception e) { System.out.println( e ) ; } } public static String accessDB( Connection con ) Metadaten der { String ausgabe="" ; // String zum Sammeln der Ausgabe try { DatabaseMetaData md = con.getMetaData(); Datenbank lesen final String[ ] tabellen = {"TABLE"}; // Hilfsvariable ResultSet tablesNames = md.getTables( null, null, null, tabellen ); while (tablesNames.next()) { String tablename = new String(tablesNames.getString(3)); ausgabe += tablename + "\n" ; } } catch (Exception e) { ausgabe += e ; } Tabellennamen der return ausgabe; Datenbank lesen } // accessDB zuende } // class dbinf zuende Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 12 Tabelle komplett lesen import java.sql.*; public class dbtab { // Main-Funktion wie in den anderen Programmen, jedoch Aufruf: // ergebnis = accessTab( con , "Auftrag" ) ; public static String accessTab( Connection con , String tabelle ) { int spalte; String ausgabe="" ; // String zum Sammeln der Ausgabe try { Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select * from " + tabelle); ResultSetMetaData rsmd= rs.getMetaData(); int spaltenAnzahl = rsmd.getColumnCount(); for( spalte=1 ; spalte <= spaltenAnzahl ; spalte++ ) { ausgabe += rsmd.getColumnLabel( spalte ) + "\t\t" ; } ausgabe += "\n-------------------------------------\n" ; while (rs.next()) { for( spalte=1 ; spalte <= spaltenAnzahl ; spalte++ ) { ausgabe += rs.getString(spalte) + "\t" ; } ausgabe += "\n" ; } } catch (Exception e) { ausgabe += e ; } return ausgabe; } // accessTab } // class dbtab zuende Metadaten der Tabelle lesen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 13 Zugriff auf Oracle-Datenbanken • Treiber laden Class c = Class.forName("oracle.jdbc.OracleDriver"); // Treiber für Oracle • Verbindung herstellen Connection con = DriverManager.getConnection( "jdbc:oracle:thin:@131.234.48.168:1521:oradb01", "oracle_login" , "oracle_passwort " ); Internetadresse Port Datenbank • Alles weitere wie für Access: Statement-Objekt definieren, Datenbank zugreifen, Statement und Verbindung zum DBMS schließen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 14 Zugriff auf Sybase-Datenbank (unter Unix) • Treiber laden Class c = Class.forName(“com.sybase.jdbc.SybDriver"); • Verbindung herstellen con = DriverManager.getConnection ( "jdbc:sybase:Tds:beethoven.uni-paderborn.de:4100/kunden", "userid", "password" ); Internetadresse Port Datenbank • Alles weitere wie für Access: Statement-Objekt definieren, Datenbank zugreifen, Statement und Verbindung zum DBMS schließen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 15 Zugriff auf MySQL-Datenbank • Treiber laden Class c = Class.forName(“com.mysql.jdbc.Driver"); • Verbindung herstellen con = DriverManager.getConnection ( "jdbc:mysql://beethoven.uni-paderborn.de:3306/kunden", "userid", "password" ); Internetadresse Port Datenbank • Alles weitere wie für Access: Statement-Objekt definieren, Datenbank zugreifen, Statement und Verbindung zum DBMS schließen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 16 Zugriff auf Excel-Tabellen • Treiber laden Class c = Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Verbindung herstellen con = DriverManager.getConnection( "jdbc:odbc:odbc2excel" ); ? Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 17 Zugriff auf Excel-Tabellen Untere rechte Ecke einer Excel-Tabelle für die ODBCVerarbeitung bekannt machen Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 18 Beispielprogramme zu JDBC dbinit.java Datenbank-Initialisierung dbselect.java Selektion von Datenbankinhalten dbinf.java Information über das Datenbankschema lesen nutzt Metadaten der Datenbank dbtab.java Eine beliebige Tabelle ausgeben nutzt Metadaten der auszugebenden Tabelle exinit.java, …, extab.java , orainit.java, sybinit.java dasselbe für Excel, Oracle und Sybase Quellcode in .zip-Datei Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 19 Prepared Statements Statt Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery( "select * from liefert where teil = '" + pc + "';") ; wird folgendes verwendet PreparedStatement pstmt = con.prepareStatement( "select * from liefert where teil = ?"); pstmt.setString(1, pc); ResultSet rs = pstmt.executeQuery(); Vorteile: • effizienter verarbeitbar durch DBMS • verhindert SQL-Injection , d.h. Übergabe pc=" 'pc1' union select login, password from usertable" Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 20 Datenbank lesen mit Prepared Statements import java.sql.*; public class dbselectps { public static void main( String[] args ) { … } public static String selectTab( Connection con, String limit ) { String ausgabe="" ; // String zum Sammeln der Ausgabe try { PreparedStatement pstmt = con.prepareStatement( "SELECT * FROM Liefert WHERE Preis < ?“ ) ; // ? Gibt Parameter an pstmt.setString(1, limit); ResultSet rsLiefert = pstmt.executeQuery(); ausgabe += "\n\nLiefert:\n( Lieferant Teil Preis Lieferzeit )" ; while (rsLiefert.next()) // hole nächstes Tupel aus Result-Set { ausgabe += "\n" + rsLiefert.getString("Lieferant") + " " + rsLiefert.getString("Teil") + " " + rsLiefert.getInt("Preis") + " " + rsLiefert.getInt("Lieferzeit") ; } rsLiefert.close() ; pstmt.close() ; // ResultSet schließen , Statement schließen } catch (Exception e) { ausgabe += "\nFehler bei Anfrage an die Datenbank:\n" + e ; } return ausgabe ; } // Funktion selectTab zuende } // class dbselectps zuende Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 21 Embedded SQL - Überblick alternative Einbettung von SQL in Gastsprache (z.B. C, C++, COBOL, Ada, Pascal) Standard seit 1992 Kommunikation mit der Gastsprache über besonders gekennzeichnete Variablen Precompiler übersetzt EXEC SQL-Befehle in die Gastsprache Vorteil: SQL-Syntax und Typverträglichkeit der Schnittstelle sind bereits zur Compilezeit prüfbar Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 22 Embedded SQL - Beispiel // zeige Durchschnittsbetrag aller Konten – wenn es Konten gibt EXEC SQL select Count(KontoNr) into :Kontenanzahl from Konten if ( Kontenanzahl ≠ 0 ) Attribut der Relation Variable der Gastsprache Datenbankrelation { EXEC SQL select SUM(KontoStand) into :Summe from Konten println(''Durchschnittsbetrag ist :'', Summe / Kontenanzahl ) ; } Grundlagen von Datenbanken - SS 2010 - Prof. Dr. Stefan Böttcher – JDBC / Folie 23