JAVA zum Zugriff auf Datenbanken JDBC Sven Frimont 15.01.2001 1. 2. 3. 4. 5. 6. 7. Überblick Treiber und Datenbankverbindung Ausführung von SQL-Anfragen ResultSet: Ergebnisse von Anfragen Abbildung von SQL-Typen in Java DBMS-Unabhängige Programmierung Vorteile der Programmierung einer Datenbankanwendung in Java JDBC... • ...steht (inoffiziell) für Java Database Connectivity • ...gehört seit Java 1.1 zur Standard-API von Java • ...ermöglicht Java-Programmen einen Zugriff auf relationale DBMS • ...besteht aus Klassen und Interfaces Historie von JDBC • Ab Java 1.1 ist JDBC Bestandteil des Standard-API von Java • Die aktuelle Version: JDBC 2.1 • Spezifikation im ‚Alpha Draft‘: JDBC 3.0 Wie können Programmiersprache und ein DBMS gekoppelt werden? • Prozedurale Schnittstelle • Spracherweiterungen / neue Sprachentwicklungen • Einbettung einer Datenbanksprache in die Programmiersprache • statisch: Datenbank-Anweisungen müssen zur Übersetzungszeit feststehen • dynamisch: Ermöglicht Konstruktion der Datenbank-Anweisungen zur Laufzeit Wie sind Java und ein DBMS durch JDBC gekoppelt? • JDBC kombiniert – prozedurale Schnittstelle mit – dynamischer SQL-Einbettung Wichtige Interfaces des JDBC-API – Connection • repräsentiert eine Verbindung zu einer Datenbank – Statement • Ermöglicht die Ausführung von SQL-Anweisungen über eine gegebene Verbindung (Connection) – ResultSet • ermöglicht den Zugriff auf das Ergebnis einer mit einem Statement ausgeführten SQL-Anfrage Wichtige Interfaces des JDBC-API Connection createStatement Statement Statement executeQuery ResultSet ResultSet JDBC-Treibertypen Java-Anwendung JDBC-Treibermanager JDBC-ODBCBridge-Treiber Native-APITreiber ODBC-Treiber ClientBibliothek ClientBibliothek Typ 1 JDBC-NetTreiber NativeProtokollTreiber Middleware Typ 2 Typ 3 Typ 4 Ein JDBC-Treiber... • Implementiert die Interfaces von java.sql, dem JDBC API package, d.h. unter anderem auch Driver, Connection, Statement und ResultSet • Der Konstruktor der Klasse Driver trägt eine Instanz der Klasse Driver durch Aufruf der Methode DriverManager.registerDriver(new name.des.treibers) in die in der Klasse DriverManager existierende Liste der verfügbaren Driver Implementierungen ein Eintragen der benötigten Driver Implementierung in die Liste des DriverManager • Es gibt verschiedene Möglichkeiten den Konstruktor einer Driver Implementierung auszuführen: 1. Mit new eine neue Instanz der Klasse erzeugen 2. Alle Driver Implementierungen die in der Systemeigenschaft (Property) sql.drivers eingetragen sind, werden vom DriverManager beim Start automatisch geladen 3. Durch einen Seiteneffekt der Methode Class.forName(“Name des Treibers“) Herstellen einer Verbindung über die Klasse DriverManager 1. 2. 3. Die Methode DriverManager.getConnection bekommt eine URL als Parameter übergeben. Der DriverManager versucht nacheinander mit den Driver Implementierungen in der Liste eine Verbindung zur Datenbank aufzubauen Wenn ein zu der URL passender Treiber gefunden und die Verbindung aufgebaut wurde, gibt getConnection die Connection Implementierung dieses Treibers an die Anwendung zurück Beispiel: Eine JDBC-URL Subprotokoll Treiber-Art Oracle Instanz JDBC:ORACLE:THIN:@polaris:1521:ORCL Netzadresse Portnummer Programmbeispiel: Herstellen einer Verbindung über die Klasse DriverManager Die Klasse Driver dynamisch laden Class.forName(“org.gjt.mm.mysql.Driver“) String URL = “jdbc:mysql://localhost/test“; String user = “sven“; passwd = “ibikom“; Connection con = DriverManager.getConnection(url, user, passwd); Die zum Treiber gehörende Implementierung des Interfaces Connection anfordern Probleme der Treiber-Verwaltung mit der Klasse DriverManager • Properties können nicht in jeder Situation verwendet werden • Wenn Class.forName(String treibername) verwendet wird, bleibt es dem Programmierer überlassen wo und wie der treibername gesetzt wird Falls später ein anderer Treiber verwendet werden soll muss der Programm-Code evtl. verändert werden! Herstellen einer Verbindung über eine Implementierung des DataSource interfaces • Das DataSource Interface... – ...repräsentiert eine Daten-Quelle und liefert Verbindungen mit dieser. – ...wird vom JDBC-Treiber implementiert • Eine Implementierung dieses Interfaces besitzt eine Reihe von Eigenschaften (Properties) welche die Datenquelle identifizieren und beschreiben • Ein DataSource Objekt kann in einem Naming Service abgelegt und anschliessend vom Java-Programm über einen Namen (über die JNDI-Implementierung des Naming Service) angesprochen werden. bei einem Wechsel der DataSource ist keine Änderung im Programm-Code notwendig! Programmbeispiel: Herstellen einer Verbindung über eine in einem Naming Service abgelegte DataSource Context ctx = new InitialContext(); In JNDI werden alle Naming-Operationen relativ zu einem Context ausgeführt DataSource ds = (DataSource)ctx.lookup(“jdbc/RezeptDatenbank“); Connection con = ds.getConnection(“user“,“pwd“); Gibt eine Connection Implementierung zurück Gibt das Objekt zurück das an den Namen “jdbc/RezeptDatenbank“ gebunden ist Wichtige Interfaces des JDBC-API Connection createStatement Statement Statement executeQuery ResultSet ResultSet Programmbeispiel: Ein Statement Objekt erzeugen und eine SQL-Anweisung an das DBMS übermitteln mit der Connection Implementierung ein Statement erzeugen Statement stmt = con.createStatement(); String query = “SELECT Name, Vorname FROM Person“; ResultSet rs = stmt.executeQuery(query); Über das ResultSet Objekt kann anschliessend auf das Ergebnis der Anfrage zugegriffen werden SQL-Anweisung übermitteln Wichtige Interfaces des JDBC-API Connection createStatement Statement Statement executeQuery ResultSet ResultSet Der Zugriff auf die Daten im ResultSet über einen Cursor Spaltennamen Nr 1 3 6 20 30 33 Name Theke Backe Mussmal Übel Moll Bolika Vorname Anna Anna Machbald Ismir Tesa Anna ResultSet Cursor Steuern des Cursors im ResultSet • Verschiedene Methoden zur Steuerung der Position des Cursors: next(), previous(), first(), last(), ... • Der Cursor ist anfangs vor dem ersten Tupel positioniert Vor dem Lesen muss next() aufgerufen werden! • next() liefert bei erfolgreicher Ausführung den Wert true zurück Abbildung zwischen Java- und JDBC-Typen JDBC-Typ Java-Typ CHAR String VARCHAR String NUMERIC java.math.BigDecimal INTEGER int ... ... Programmbeispiel: Das Auslesen des ResultSet bereits bekannt... ResultSet rs = stmt.executeQuery( “SELECT Nr, Name, Vorname from Person“); INTEGER While (rs.next()) { int nr = rs.getInt(“Nr“); VARCHAR String Name = rs.getString(“Name“); String Vorname = rs.getString(“Vorname“); System.out.println(nr + “ } “ + name + “ “ + vorname); SQL-Statements die kein Ergebnis liefern • Neben SQL-Anfragen können auch – Einfüge- (INSERT), – Änderungs-(UPDATE), Lösch-(DELETE) und – DDL-Operationen(z.B. CREATE TABLE, DROP TABLE ) durchgeführt werden • Für diese SQL-Operationen gibt es die Methode executeUpdate, sie liefert als Ergebnis die Anzahl der betroffenen Tupel der Relation int rows = stmt.executeUpdate( “UPDATE Person SET Name = ‘Dur‘ WHERE Vorname= ‘Moll‘“); Transaktionssteuerung • Es sind Kommandos zur Steuerung des Transaktionsablaufes im Connection Interface definiert: – void commit() – void rollback() • Nachdem eine Verbindung zur Datenbank hergestellt wurde umfasst eine Transaktion jeweils nur eine Anweisung, dieser Modus kann mit der Methode setAutoCommit(false) ausgeschaltet werden Erweiterungen des Statement Interface • Das PreparedStatement Interface erweitert Statement Statement – Eine SQL-Anweisung kann mehrfach, mit verschiedenen Werten als Parameter, ausgeführt werden PreparedStatement • Das CallableStatement Interface erweitert PreparedStatement – Unterstützung von Stored Procedures CallableStatement Programmbeispiel: Anwenden eines PreparedStatement String insStr = Platzhalter “INSERT INTO Person VALUES (?,?,?)“; PreparedStatement updStmt; updStmt = con.prepareStatement (insStr); updStmt.setInt(1,123); updStmt.setString(2,“Meier“); updStmt.setString(3,“Hans“); updStmt.executeUpdate(); Die Werte einsetzen DBMS-unabhängige Programmierung • Escape Sequenzen • DatabaseMetaData zum Abfragen der Fähigkeiten eines DBMS Escape Sequenzen • In einem Statement enthaltene DBMSunabhängige Escape Sequenzen werden durch den Treiber in die Syntax des DBMS übersetzt • Escape Sequenzen gibt es z. B. für: – Skalare Funktionen z. B. {fn <function-name> (argument list)} – Outer joins z. B. {oj Table1 LEFT OUTER JOIN Table2 ON Nr=6} – Stored procedures z. B. {call <procedure_name> [(<arg-list>)]} – Datumsangaben z. B. {d ´1997-07-24‘} Informationen über das DBMS: Das DatabaseMetaData Interface • Über 150 Methoden, die Informationen über die Datenbank und das DBMS liefern: – Methoden die Informationen über die Datenbank liefern – Methoden, die die unterstützten Features charakterisieren – Methoden, die die Zulässigkeit von DDLAnweisungen als Teil von Transaktionen spezifizieren Was wurde nicht besprochen? • • • • • • Einige ResultSet-Erweiterungen Batch-Updates SQL99-Datentypen Connection Pooling Verteilte Transaktionen RowSets Vorteile der Programmierung einer Datenbankanwendung in Java • Der Datenbank-Client ist durch Java unabhängig von einer bestimmten Zielplattform • Die Anwendung ist (im Idealfall) unabhängig vom Datenbankmanagementsystem