JDBC Literatur Ausgewählte Implementierungsprobleme Rebecca Tiarks 22. Januar 2009 1 / 50 JDBC Literatur Inhaltsverzeichnis 1 JDBC 2 / 50 JDBC Literatur Datenbanken Sammeln, Zugreifen und Verwalten von Daten in der Computerwelt geschieht das mit Datenbanken Datenbank Management System (DBMS) verschiedene Speicherformen: relationales Modell, OO-Datenbanken, XML-Datenbanken 3 / 50 JDBC Literatur Datenbanken relationale Datenbanken bestehen aus Tabellen mit Zeilen (Tupel) und Spalten (Attribute) Zeilen einer Relation Datenbankausprägung Datenbankschema beschreibt die Struktur viele verschiedene OpenSource und kommerzielle DBs Oracle, MySQL, Microsoft Access ... Zugriff auf Datenbank in Java mit JDBC 4 / 50 JDBC Literatur JDBC Java Database Connectivity Datenbankschnittstelle für Java ist unabhängig von konkreten Datenbanksystemen unterstützt alle wichtigen Merkmale die von einer relationalen Datenbankschnittstelle erwartet werden dynamisches SQL, vorbereitetes SQL, aktualisierbare Cursor, vorwärtsscrollbare Cursor und weitere 5 / 50 JDBC Literatur Komponenten von JDBC JDBC-API zum Datenbankzugriff für Anwendungsentwickler um eine DB ansprechen können wird Treiber benötigt JDBC-Treiber stellt die Implementierung der JDBC-Schnittstelle für ein konkretes Datenbanksystem der Treiber übernimmt die Kommunikation mit dem Datenbanksystem JDBC-Treibermanager verwaltet JDBC-Treiber innerhalb der Java-Laufzeitumgebung 6 / 50 JDBC Literatur JDBC JDBC-API legt fest durch welche Methodenaufrufe man aus Java auf rel. Datenbanken zugreifen kann Schnittstelle mit Java-Interfaces die im Paket java.sql enthalten sind Zugriffsmethoden für ein konkretes Datenbanksystem (Oracle, MySQL) sind nicht enthalten Zugriff wird von JDBC-Treibern durchgeführt 7 / 50 JDBC Literatur Klassen in JDBC DriverManager wird benutzt um Verbindung zur DB aufzubauen Connection repräsentiert Verbindung wird benötigt für SQL-Anweisungen und Zugriff auf Metadaten Statement Basis-Klasse für SQL-Anweisungen PreparedStatement vorbereitete Anweisung ResultSet repräsentiert Ergebnis einer Anfrage 8 / 50 JDBC Literatur Vorgehen Registrieren des JDBC-Treibers beim Treibermanager Verbindungsaufbau zur DB SQL-Anweisung erzeugen Ausführen der SQL-Anweisung Abfragen des Ergebnisses nach der Ausführung Schließen der Datenbank Verbindung 9 / 50 JDBC Literatur JDBC-Treiber Treiber implementieren die Funktionen der JDBC-Schnittstellen aus java.sql alle Datenbank spezifischen Zugriffsmethoden sind im Treiber gekapselt die Verwaltung des Treibers übernimmt der JDBC-Treibermanager will man eine Verbindung aufbauen registriert man den Treiber beim Treibermanager bei Verbindungsaufbau zur DB wird vom Treibermanager der Treiber angefordert und initialisiert 10 / 50 JDBC Literatur Registrierung des Treibers mehrere Möglichkeiten zur Registrierung des Treibers Treiberklassen müssen sich im Klassenpfad befinden statische Methode Class.forName() erwartet vollqualifizierten Klassennamen des Treibers Klasse wird gesucht, geladen und ins Laufzeit-System eingebunden String driver = " oracle . jdb . driver . OracleDriver " ; Class . forName ( driver ); 11 / 50 JDBC Literatur Registrierung des Treibers weitere Möglichkeit Registrierung beim Aufruf des Interpreters über die Option -D die Property jdbc.drivers übergeben außerdem eine Liste von Klassennamen, die JDBC-Treiber implementieren Syntax: java - Djdbc . drivers = < treiber1 >:..: < treiberN > < Klasse > java - Djdbc . drivers = oracle . jdbc . driverOracleDriver < Klasse > 12 / 50 JDBC Literatur Verbindungs-URL in JDBC wird Datenbankserver als URL angegeben Syntax: jdbc : < protokoll >: < subprotokoll >: < datenbank > zuerst Schlüsselwort jdbc Name des verwendeten Protokolls (darunter ist der Treiber beim Treibermanager registriert) alles nach dem Protokoll ist treiberspezifisch und wird nur vom Treiber ausgewertet String url = " jdbc : h2 : testdb " ; 13 / 50 JDBC Literatur Verbindungsaufbau Verbindungsaufbau über den Treibermanager Klasse DriverManager definiert die Methode getConnection() mit jeweils unterschiedlichen Parametern als Rückgabe bekommt man ein Connection-Objekt zurück String url = " jdbc : h2 : testdb " ; Sting user = " sa " ; String password = " " ; Connection con ; con = DriverManager . getConnection ( url , user , password ); 14 / 50 JDBC Literatur Protokollierung Treibermanager-API verfügt über integrierte Protokollierungsfunktionen hilfreich zur Fehlersuche ist per Voreinstellung deaktiviert und muss explizit aktiviert werden Methode setLogWriter() kann jederzeit wieder deaktiviert werden PrintWriter logger ; logger = new PrintWriter ( new OutputStreamWriter ( System . out )) DriverManager . setLogWriter ( logger ); 15 / 50 JDBC Literatur Datenbanksprache dient zur Kommunikation zwischen Datenbanksystem und der Anwendung bzw. Benutzer Unterteilung in unterschiedliche Zwecke Datenabfrage und Manipulation: Data Manipulation Language (DML) Verwaltung der DB und Definition der Datenstruktren: Data Definition Language (DDL) Berchitigungssteuerung: Data Control Language (DCL) 16 / 50 JDBC Literatur Abfragen Abfragen sind SQL-Operationen die ein Ergebnis zurückliefern (SELECT) in Java werden Anfragen mit der Methode executeQuery() ausgeführt Methode erwartet eine gültige SQL-Anweisung (muss der Syntax des verwendeten Datenbanksystems entsprechen) liefert ein ResultSet-Objekt zurück das ReultSet repräsentiert einen Datenbank-Cursor 17 / 50 JDBC Literatur Freigabe von Ressourcen belegte Ressourcen müssen wieder freigegeben werden ResultSet, Statement und Connection verwenden große Datenstrukturen (nicht auf garbage collector warten) für alle Klassen existiert eine close() Methode nach dem Schließen ist das Objekt nicht mehr aktiv und kann nicht mehr verwendet werden ausreichend das Connection-Objekt zu schließen da alle innerhalb der Verbindung erzeugten Objekte mit geschlossen werden 18 / 50 JDBC Literatur Verbindung beenden eine Verbindung wird nach Gebrauch wieder gechlossen sehr wichtig, deshalb sollte dies immer im finally-Block geschehen da Verbindung beendet wird und nicht der DriverManager findet sich die Methode close() bem Connection-Objekt try { con = DriverManager . getConnection (...); } catch ( SQLException e ) { } finally { if ( con != null ) try { con . close ();} catch ( SQLException e ) } 19 / 50 JDBC Literatur SQL-Typen vs. Java-Typen bei Anweisungen müssen oft Parameter gesetzt werden oder Werte abgefragt werden Konvertierung zwischen Java-Typen und SQL-Typen erforderlich Type-Mapping mit JDBC 1.0 eingeführt bildet Java-Typen auf SQL-Typen ab und umgekehrt 19 Typen für die in java.sql.Types eine Konstante definiert ist die den Typ repräsentiert bei der Abfrage von ResultSet-Werten können automatisch Konvertierungen vorgenommen werden (durch getXXX()-Methoden) 20 / 50 JDBC Literatur Dynamisches vs. Vorbereitetes SQL zwei Möglichkeiten zum Ausführen von Anweisungen dynamishes SQL und vorbereitetes SQL beide setzen einen String in der Anwendung zusammen wird bei Ausführung zum Server geschickt Konstruktion kann zur Laufzeit durchgeführt werden wenn Parameteranzahl variiert einfaches SQL ansonsten vorbereitetes SQL (weniger Konvertierung, bessere Performance) 21 / 50 JDBC Literatur Dynamisches SQL komplette Anweisung wird als String zusammengestellt wird anschließend an DBS geschickt Paramter die in der Anweisung benutzt werden müssen von Hand eingebaut werden soll dieselbe Anweisung mit unterschiedlichen Parametern ausgeführt werden muss String neu zusammengesetzt werden Erzeugen eines Statement-Exemplares Aufrufen der createStatement() Methode vom Connection-Objekt aus alle Anfragen, DDL und DDM Operationen werden über Statement-Objekt durchgeführt 22 / 50 JDBC Literatur Abfragen und Operationen Abfragen werden mit der Methode executeQuery() durchgeführt Methode erwartet eine gültige SELECT-Anweisung (muss der Syntax des verwendeten Datenbanksystems entsprechen) liefert ein ResultSet-Objekt zurück executeUpdate() wird für DDL- und DDM-Operationen verwendet erwartet eine gültige INSERT, UPDATE, DELETE oder CREATE Anweisung String wird erst bei Ausführung dem Statement-Exemplar übergeben mit einem Exemplar können versch. Typen von Anweisungen ausgeführt werden 23 / 50 JDBC Literatur Beispiel String s = " SELECT * FROM test " ; String u = " UPDATE test SET wert = 2 WHERE name = 1 " ; Statement stmt = con . createStatement (); ... ResultSet res = stmt . executeQuery ( s ); ... res . close (); stmt . executeUpdate ( u ); ... stmt . close (); 24 / 50 JDBC Literatur Parameter Parameter werden über String-Operationen eingebaut Syntax des verwendeten DBS muss beachtet werden relativ einfach bei Zeichenketten und Zahlenwerten da Syntax standardisiert schwieriger bei z.B. Datums-Typen dynamische SQL-Anweisungen sind sehr allgemein definiert eignen sich wenn die Anzahl der Parameter variieren kann z.B. Suchanfrage 25 / 50 JDBC Literatur Parameter String kriterien []; Connection con ; Statement stmt = con . createStatement (); String s = " SELECT * FROM titel WHERE " ; s += " titel LIKE ’" + kriterien [0]+ " ’" ; for ( int i = 1; i < kriterien . length ; i ++){ s += " AND titel LIKE ’" + kriterien [ i ]+ " ’" ; } 26 / 50 JDBC Literatur Ergebnismengen ResultSet repräsentiert eine Ergebnismenge stellt in Java einen Datenbank-Cursor dar. ist Rückgabewert der Funktion executeQuery() aus Statement, PreparedStatement und CallableStatement bietet Zugang zu Datensätzen die vom DB-Server zurückgeliefert werden (kann auch leer sein) führt internen Datensatzzeiger (kann sich vor dem ersten und hinter dem letzten Datensatz befinden) 27 / 50 JDBC Literatur Ergebnismengen nach der Abfrage befindet sich das ReultSet vor dem ersten Datensatz Vorrücken durch next() next() liefert boolschen Wert zurück (weitere Datensätze vorhanden?) da Satzzeiger sich vor dem ersten Satz befindet muss initial next() aufgerufen werden Daten können mit getXXX() abgerufen werden als Parameter Namen oder Position einer Spalte (Pos. beginnt bei 1) 28 / 50 JDBC Literatur Typkonvertierung in JDBC können bei der Abfrage von Werten automatisch Konvertierungen durchgeführt werden getLong(), getString(), getInt() ... Connection con ; Statement stmt = con . createStatement (); String s = " SELECT titel , preis FROM titel " ; ResultSet res = stmt . execute ( s ); while ( res . next ()) { System . out . println ( " Titel " + res . getString ( " titel " ); } 29 / 50 JDBC Literatur Metadaten Informationen über Tabellen und über die Datenbank selbst verschiedene Informationen über eine DB können ausgelesen werden ist nützlich wenn man allgemeine Abfragen hat und z.B. die Anzahl der Spalten im Ergebnis nicht kennt bei Tabellen: Anzahl Spalten, Spaltentyp, NULL erlaubt, Spaltenname ... gesamte Datenbank: welche Tabellen, akt. Verbindungen, sind outer joins möglich ... 30 / 50 JDBC Literatur Metadaten von Tabellen Klasse ResultSetMetaData Resu ltSetM etaData meta = rs . getMetaData (); getColumnCount() Anzahl der Spalten getCatalogName(int column) Katalogname getColumnTypeName(int column) Spaltentyp getScale(int column) Genauigkeit der Spalte isAutoincrement(int column) Autoincrement ? isNullable(int column) darf NULL vorhanden sein? 31 / 50 JDBC Literatur Metadaten der Datenbank Klasse DatabaseMetaData DatabaseMetaData meta = con . getMetaData (); getDatabaseProductName() getMaxConnections() getDriverVersion() getTableTypes() supportsOuterJoins() ... 32 / 50 JDBC Literatur Positionierung seit JDBC 2.0 möglich sich in einer Ergebnismenge zurück zu bewegen außerdem direkt eine Zeile anwählbar Konstanten aus dem ResultSet-Interface definieren Positionierbarkeit beim Erzeugen des Statements wird Konstante übergeben FORWARD ONLY nur vorwärts TYPE SCROLL INSENSITIVE vorwärts, rückwärts, absolut bekommt Änderungen aus anderen Sitzung nicht mit TYPE SCROLL SENSITIVE vorwärts, rückwärts, absolut bekommt Änderungen aus anderen Sitzung mit 33 / 50 JDBC Literatur Positionierung Methoden eines positionierbaren ResultSets previous() zurück first() erster Datensatz last() letzter Datensatz beforeFirst() vor den ersten afterLast() nach den letzten absolute(int) springe zu Nummer Datensatz relative(int) verändere aktuelle Position 34 / 50 JDBC Literatur Verändern von Datensätzen seit JDBC 2.0 aktueller Datensatz veränderbar über updateXXX() mit konkretem Datentyp CONCUR READ ONLY nicht änderbar CONCUR UPDATETABLE änderbar 1. Statement Exemplar erzeugen 2. Anfrage ausführen ResultSet positionieren 3. Änderung über ResultSet-Methoden updateRow(), deleteRow(), insertRow() 35 / 50 JDBC Literatur Verändern von Datensätzen Connection con ; Statement stmt = con . createStatement ( ResultSet . TYPE_SCROLL_INSENSITIVE , ResultSet . CONCUR_UPDATEABLE ); String s = " SELECT tit_id , preis FROM titel WHERE tit_id = 2 " ; ResultSet res = stmt . executeQuery ( sql ); rs . next (); rs . updateFloat (2 ,50); rs . updateRow (); ... 36 / 50 JDBC Literatur Größe der Ergebnismenge entweder mit zwei Abfragen oder mit Positionierung von JDBC 2.0 Result res = stmt . executeQuery ( " SELECT count (*) FROM titel " ); res . next (); long length = res . getLong (1); res . close (); // eigentliche Anfrage Statement stmt = con . createStatement ( ResultSet . TYPE_SCROLL_INSENSITIVE , ResultSet . CONCUR_READ_ONLY ); Result res = stmt . executeQuery ( " SELECT preis , name FROM titel " ); res . last (); long length = res . getRow (); res . first (); // Zugriff auf Daten 37 / 50 JDBC Literatur Vorbereitetes SQL Platzhalter für Parameter in Anweisungen werden bei Ausführung mit Werten belegt dadurch Anweisungen mehrfach verwendbar Parameter werden durch ? definiert Erzeugen eines PreparedStatements mit prepareStatement()-Methode SQL-Anweisung + Parameter Definition werden übergeben mit setXXX()-Methoden werden Parameter mit Werten belegt (XXX für Datentyp) 38 / 50 JDBC Literatur Vorbereitetes SQL beim Erzeugen wird SQL-String an DBS geschickt, kompiliert und zwischengespeichert mit Lücken für Parameter erst beim Aufruf der setXXX()-Methoden gesetzt setXXX() kann Parameter immer wieder neu setzen die initial kompilierte Anweisung wird wiederverwendet nur mit neuen Parametern bessere Performance 39 / 50 JDBC Literatur Parameter setzen setXXX() erwartet Index des Parameters und Wert bei mehrfachem Ausführen müssen nicht alle Werte neu belegt werden Wert bleibt solange gültig bis er durch neuen ersetzt wird Löschen der Parameter mit clearParameters() NULL-Werte sind setzbar durch setNull() oder NULL 40 / 50 JDBC Literatur Parameter setzen long titId ; long words []; String sql = " INSERT INTO stichworte_titel VALUES (? ,?) " ; PrepareStatement stmt = con . prepareStatement ( sql ); stmt . setLong (2 , titId ); for ( int i =0; words . length ; i ++) { stmt . setLong (1 , words [ i ]); stmt . executeUpdate (); } 41 / 50 JDBC Literatur Stored Procedures CallableStatement in JDBC abgeleitet von PreparedStatement prepareCall() erzeugt CallableStatment Rückgabewerte müssen vor Ausführung definiert werden registerOutParameter() Parameter setzen setXXX() Aufrufen von executeUpdate() { ? = call funktion (? , ?) } { call funktion (? , ?)} 42 / 50 JDBC Literatur Stored Procedures Stored Functions besitzt einen Rückgabewert Stored Procedures und Functions können OUT oder IN OUT Parameter definieren String isbn ; int rank ; String sql = " { ? = call ranking (?) } " ; CallableSt atemen t call = con . prepareCall ( sql ); call . setString (2 , isbn ); call . re g i s t e r O u t P arameter (1 , Types . NUMERIC ); call . executeUpdate (); rank = call . getInt (1); 43 / 50 JDBC Literatur Large Objects große Daten in Datenbanken zwei Typen BLOBs und CLOBs in JDBC Schnittstelle zum Zugriff auf Large Objects werden über Streams vom DBS gelesen, bzw. geschrieben Schreiben vom Large Objects nur mit PreparedStatement bzw. CallableStatement-Exemplaren 44 / 50 JDBC Literatur Zugriff auf BLOB und CLOB Zugriff über getBlob() und getClob() Setzen über setBinaryStream() da es keinen eigenen Konstruktor gibt NEU seit Java 6: createBlob(), und CreateClob() PreparedSt atemen t stmt = con . prepareStatement ( " INSERT INTO MyTable column VALUES (?) " ); File file = new File ( " myImage . jpg " ); InputStream in = new FileInputStream ( file ); stmt . setBinaryStream ( 1 , in , ( int ) file . length ()); stmt . executeUpdate (); 45 / 50 JDBC Literatur Transaktionen sind durch folgende Eigenschaften charakterisiert Atomic (atomar): zu einer Transaktion können mehrere primitive Änderungen gehören von denen entweder alle oder keine augeführt wird Consistent (kosistent): überführen Datenbank von einem konsistenten Zustand in einen anderen konsitenten Zustand Isolated (isoliert): Einzelschritte beliben für andere Sitzungen verborgen Durable (dauerhaft): Änderungen werden dauerhaft gespeichert 46 / 50 JDBC Literatur Transaktionen nach dem Öffnen einer Verbindung wird automatisch neue Transaktion gestartet Auto-Commit-Modus nach jeder Ausführung wird die Änderung gespeichert nach der Ausführung neue Transaktion Commit-Modus kann über die Methode setAutoCommit() beeinflusst werden getAutoCommit() fragt Zustand ab 47 / 50 JDBC Literatur Transaktionen liefert getAutoCommit() false muss man Transaktionen selber steuern commit() beendet Transaktion und speichert Änderungen rollback() Änderungen die seit dem letztn commit() gemacht wurden werden verworfen Connection con = DriverManager . getConnection ( url , user , password ); con . setAutoCommit ( false ); Statement stmt = con . createStatement (); ... try { stmt . executeUpdate ( up1 ); stmt . executeUpdate ( up2 ); con . commit (); } catch ( SQLException e ) { con . rollback (); } 48 / 50 JDBC Literatur Übungsaufgaben embedded Datenbank da einfach aufzusetzen 100% Java nur ein Jar und DB als 3 Dateien hier H2 (http://www.h2database.com/) Treibername: org.h2.Driver Url-Syntax: “jdbc:h2:/tmp/testdb “ wobei “/tmp/testdb“ der Dateiname der DB ist Username ist “sa“, Passwort leer Datenbank wird automatisch erzeugt Webinterface auf dem lokalen Rechner h2/bin/h2.jar muss zum Classpath hinzugefügt werden 49 / 50 JDBC Literatur Cay S Horstmann and Gary Cornell. Core Java. Revised and Updated for Java SE 6; 8th ed. Prentice-Hall, Upper Saddle River, NJ, 2008. Christian Ullenboom. Java ist auch eine Insel. Galileo Computing, 7 edition, 2008. ISBN 978-3-8362-1146-8. 50 / 50