Hochschule München Abbildung 1: JDBC1 Gracin Denis Betreuer: Dipl.-Inform. Michael Theis Fach: Aktuelle Technologien zur Entwicklung verteilter Java-Anwendungen 1 http://howtodoinjava.com/wp-content/uploads/JDBC-Icon.png Inhaltsverzeichnis Abbildungsverzeichnis ................................................................................................ 3 Tabellenverzeichnis.................................................................................................... 3 Listingverzeichnis ....................................................................................................... 3 1 Einleitung................................................................................................................. 4 2 Begriffsklärung......................................................................................................... 4 2.1 JDBC................................................................................................................. 4 2.2 Datenbanksystem ............................................................................................. 4 3 MySQL Datenbankserver ........................................................................................ 5 4 Grundlagen zu JDBC API ........................................................................................ 6 4.1 Architektur von JDBC API ................................................................................. 6 4.2 Treiber von JDBC API....................................................................................... 8 4.2.1 Typ-1 Treiber.............................................................................................. 8 4.2.2 Typ-2 Treiber: ............................................................................................. 9 4.2.3 Typ-3 Treiber............................................................................................ 10 4.2.4 Typ-4 Treiber............................................................................................ 10 4.3 Verbindungsablauf .......................................................................................... 11 5 Datenbankzugriff mit JDBC ................................................................................... 13 5.1 Verbindungsaufbau ......................................................................................... 13 5.2 Übermitteln von Abfragen ............................................................................... 14 5.3 Ergebnisverwaltung ........................................................................................ 17 5.3.1 Konfiguration eines ResultSet .................................................................. 17 5.3.2 Änderung am ResultSet ........................................................................... 19 5.4 Schließen der Verbindungen........................................................................... 20 6 JDBC mit Spring Framework ................................................................................. 21 7 Fazit....................................................................................................................... 24 8 Literaturverzeichnis ............................................................................................... 24 2 Abbildungsverzeichnis Abbildung 1: JDBC ..................................................................................................... 1 Abbildung 2: Lokaler Datenbankserver....................................................................... 5 Abbildung 3: 2-Schichten-Modell ................................................................................ 6 Abbildung 4: 3-Schichten-Modell ............................................................................... 7 Abbildung 5: Typ -1 Treiber ........................................................................................ 8 Abbildung 6: Typ -2 Treiber ........................................................................................ 9 Abbildung 7: Typ -3 Treiber ...................................................................................... 10 Abbildung 8: Typ -4 Treiber ...................................................................................... 10 Abbildung 9: Ablauf .................................................................................................. 11 Tabellenverzeichnis Tabelle 1: Datenbank-URLs ..................................................................................... 13 Listingverzeichnis Listing 1: Verbindungsaufbau zur Datenbank ........................................................... 14 Listing 2: Übermittlung der Abfrage .......................................................................... 15 Listing 3: Update-Methode........................................................................................ 15 Listing 4: Update mit PreparedStatement................................................................. 16 Listing 5: ResultSet einstellen................................................................................... 17 Listing 6: Aktualisierung eines ResultSet.................................................................. 19 Listing 7: Try-Catch Block für jede Verbindung......................................................... 20 Listing 8: Beans.xml ................................................................................................. 21 Listing 9: Verbindungsaufbau zur Datenbank ........................................................... 22 Listing 10: Datensatz in ein Student-Objekt speichern ............................................. 22 Listing 11: Speichert die Datenbanktabelle .............................................................. 23 Listing 12: Datenbank aktualisieren.......................................................................... 23 3 1 Einleitung Diese Arbeit soll dem Leser ein Grundverständnis für den Aufbau und die Nutzung von JDBC in Verbindung mit einer MySQL Datenbank vermitteln. Außerdem sollen die Vorzüge des Spring Frameworks näher erläutert werden. Hierzu wurde ein Lokaler MySQL Datenbankserver eingerichtet und zwei kleine Java-Programme geschrieben, welche auf den besagten Server zugreifen. 2 Begriffsklärung 2.1 JDBC Seit JDK 1.1 ist JDBC Bestandteil der Java Bibliothek. JDBC steht für "Java Database Connectivity" und ist an Microsofts ODBC, "Open Database Connectivity", angelehnt. Da aber ODBC mit C-Sharp realisiert wurde, konnte es nicht komplett übernommen werden und musste an das Objektorientierte Design von Java angepasst werden. JDBC stellt einen einfachen Mechanismus bereit, der einen leichten Zugriff auf Datenbanksysteme ermöglicht. Dabei nehmen Treiber die Schnittstellen zwischen dem Programm und der Datenbank ein. Da sich der Quellcode im Wesentlichen nicht ändert, kann man mit diesem, auf jede beliebige Datenbank zugreifen, sofern Treiber dafür existieren. Dies verdanken wir unter anderem auch der 2 Standarddatenbanksprache SQL, "Structured Query Language". 2.2 Datenbanksystem Der Zugriff und die Verwaltung von Informationen spielen heutzutage eine immer größere Rolle, egal ob für Unternehmen, Wissenschaftler, etc. Um diese enorme 2 http://www.java.seite.net/jdbc/index.html (aufgerufen am 05.05.2014) 4 elektronischen Datenmengen, die sich laut Statistiken alle 5 Jahre verdoppeln, in den Griff zu bekommen musste etwas entwickelt werden. Deshalb wurde ein Datenbankverwaltungssystem, oder auch nur Datenbanksystem, entwickelt um auf diese Daten schnell zugreifen und diese verwalten zu können.3 Mittlerweile gibt es eine Vielzahl an verschiedenen Datenbanksystemen, welche die Daten auf verschiedene Art und Weise speichern und verwalten. Für diese Studienarbeit verwende ich eine relationale Datenbank. Eine relationale Datenbank besteht aus beliebig vielen Tabellen, die sich auf beliebige Art und Weise verknüpfen lassen. Die Daten werden in Spalten, sogenannten Attributen, und Reihen als Datensätze gespeichert. Wichtig ist, dass die Daten richtig, also dem Datentyp entsprechend, gespeichert werden und keine Doppelungen vorkommen dürfen.4 3 MySQL Datenbankserver Wie in der Einleitung bereits erwähnt, wurde für diese Studienarbeit ein lokaler Datenbank-Server eingerichtet. Abbildung 2: Lokaler Datenbankserver Um den Server zu verwalten, wurde das Programm "MySQL Workbench 6.1" installiert. Dieses kann man kostenlos auf der Oracle Webseite herunterladen. Mit 3 Datenbanksysteme - Alfons Kemper, André Eickler S.21 http://www.itwissen.info/definition/lexikon/Relationale-Datenbank-database-relational.html (aufgerufen am 05.05.2014) 4 5 diesem Programm lassen sich einfache Schemen, also Datenbanken, erstellen und bearbeiten. Wie sich herausstellte war die Einrichtung des Datenbanksystems schnell erledigt und nach einer kurzen Einarbeitung konnte man die wichtigsten Funktionen aneignen. Für die geschriebenen Java Programme wurden zwei Datenbanken mit den Namen "filme" und "student" erstellt. Die Datenkbank "filme" enthält eine Tabelle "Filme". Das zweite Programm greift auf die Datenbank "student" zu, verhält sich aber vom Ablauf anders. Es stellt eine Verbindung her, erstellt eine Tabelle "Student", befüllt diese und löscht sie dann wieder. Neue Benutzer können schnell erstellt werden und die Rechteverwaltung ist auch benutzerfreundlich angelegt, so kann man z.B. die maximale Anzahl der Queries, die ein Benutzer pro Stunde abgeben darf, limitieren. Auch kann man einstellen, ob der Benutzer über Lese- oder auch Schreibrechte verfügen soll. 4 Grundlagen der JDBC API 4.1 Architektur der JDBC API Die JDBC Architektur unterstützt das 2-Schichten- und 3-Schichten-Modell. Abbildung 3: 2-Schichten-Modell 5 Im 2-Schichten-Modell greift der Benutzer direkt auf die Datenbank zu, hierfür wird ein JDBC-Treiber benötigt, um eine Verbindung aufzubauen. Sobald eine Verbindung aufgebaut wurde, können die Datenbankbefehle direkt an die Datenbank 5 http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html (aufgerufen am 22.04.2014) 6 gesendet werden und der Benutzer erhält die Ergebnisse der ausgeführten Abfrage. Normalerweise ist die Zielquelle auf einem entferntem Server, welcher mit einem Netzwerk, sei es Internet oder Intranet, verbunden ist. Hier fungiert der Benutzer als Client und der Server als Host.6 Abbildung 4: 3-Schichten-Modell 7 Im 3-Schichten-Modell werden die Datenbankbefehle an eine mittlere Schicht übermittelt, die diese Abfrage dann weiter an die Datenbank übergibt. Die Datenbank verarbeitet die erhaltenen Befehle und sendet die Rückgabe zurück an die mittlere Schicht, diese wiederum zurück zum Benutzer. Ein Vorteil dieses Verfahrens ist, dass die Programme einfacher gestaltet sind, da man sich nicht mehr um die Datenbank Verbindung kümmern muss. Die mittlere Schicht ist meist in C oder C++ geschrieben, da diese Programmiersprache die beste Perfomance liefern. Mit der Optimierung der Compiler, welche Java Bytecode in effizienten Maschinen-Code kompiliert, gewinnt die Java Plattform für die mittlere Schicht immer mehr an Bedeutung. Da die Unternehmen immer mehr Java als Serversprache verwenden, bekommt JDBC als mittlere Schicht eine immer größere Bedeutung. Einige der Funktionen, wie "connection pooling", "distributed transactions" und "disconnected rowsets", machen JDBC zu einer guten Server Technologie. 8 6 http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html (aufgerufen am 22.04.2014) http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html (aufgerufen am 22.04.2014) 8 http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html (aufgerufen am 22.04.2014) 7 7 4.2 Treiber von JDBC API 4.2.1 Typ-1 Treiber Abbildung 5: Typ -1 Treiber Typ-1, auch bekannt als JDBC-ODBC-Bridge, fungierte anfangs, wie der Name schon sagt, als Brücke zwischen einer Java Anwendung und der damals genormten ODBC Schnittstelle von Microsoft. Diese wandelte die clientseitigen Aufrufe von JDBC in ODBC-Aufrufe um. Damit diese Umwandlung funktioniert, ist die Installation eines ODBC-Treibers notwendig und daher ungeeigenet für den Einsatz im Internet. Außerdem ist zu erwähnen, dass der Typ-1-Treiber native Methoden besitzt und diese Methoden ebenfalls den Einsatz über das Internet erschweren. Native Methoden sind Methoden, die in einer anderen Sprache beginnen und so auf systemspezifische Funktionen zugreifen, die in der Java-API nicht vorhanden sind .9 Diese Methode wird heutzutage dann verwendet, wenn die Datenbank nur ODBCTreiber verwendet und keine JDBC-Treiber installiert hat.10 9 http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzaha%2Fnmjni.htm http://www.itwissen.info/definition/lexikon/Applet-applet.html, http://www.schuenemann.name/studium/sim3D/sim3d-kap2.html (jeweils am aufgerufen 07.05.2014) 10 8 4.2.2 Typ-2 Treiber Abbildung 6: Typ -2 Treiber Typ-2 Treiber übersetzen die JDBC-Aufrufe direkt in Aufrufe der Datenbank-API. Wie Typ-1 enthält auch Typ-2 native Methoden. Somit ist der Client abermals aufgefordert, die zusätzlichen Treiber auf dem System zu installieren. Da die Treiber von den Typen 1 und 2 auf native Methoden zurückgreifen müssen, sind diese nicht portabel, da sie auf plattformspezifische Zugriffsmöglichkeiten für die Datenbank angewiesen sind. Der Nachteil ist, dass Applets (ein Computerprogramm, das nicht als eigenständige Applikation betrieben wird, siehe Widget) 11 mit diesen Treibern nicht umgehen können. Einem Applet ist es nicht erlaubt, auf nativen Code zuzugreifen und kann deshalb keine Verbindung zu einer Datenbank herstellen. 11 http://www.itwissen.info/definition/lexikon/Applet-applet.html, http://www.schuenemann.name/studium/sim3D/sim3d-kap2.html (jeweils am aufgerufen 07.05.2014) 9 4.2.3 Typ-3 Treiber Abbildung 7: Typ -3 Treiber Mittels des Typ-3 Treibers werden die JDBC-API-Befehle in ein generisches Datenbankmanagementsystem (DBMS) übersetzt und an einen Middleware-Treiber auf einen Anwendungsserver übertragen. Erst der Anwendungsserver transformiert die Befehle für den jeweiligen Datenbankserver um und leitet diese weiter. Typ-3 eignet sich im Zusammenhang mit Firewalls sehr gut für Internet-Protokolle. Das besondere an Typ-3 ist, dass der Client keine spezifische Bibliothek installieren muss und er keine Informationen über den Datenbankserver benötigt.12 4.2.4 Typ-4 Treiber Abbildung 8: Typ -4 Treiber13 12 openbook.galileocomputing.de/javainsel9/javainsel_24_003.htm, http://www.schuenemann.name/studium/sim3D/sim3d-kap2.html (jeweils am aufgerufen 07.05.2014) 13 Abbildung 5-8 http://www.schuenemann.name/studium/sim3D/sim3d-kap2.html#Kapitel21 10 Der Typ-4 Treiber ist vollständig in Java programmiert und kommuniziert auf direktem Wege mit dem Datenbankserver. Hier werden die JDBC-API Befehle direkt an das DMBS gesendet und anschließend für den jeweilige Datenbankserver übersetzt und übertragen. Durch die direkte Verbindung mit der Datenbank ist Typ-4 schneller als Typ-3. Dafür ist Typ-4 weniger flexibel. Da der Server die Befehle übersetzt, muss auch hier keine Bibliothek vorhanden sein. Wegen der schnellen Verbindung eignet sich Typ-4 gut für das Intranet.14 4.3 Verbindungsablauf In diesem Abschnitt werden die Schritte eines Verbindungsablaufs erläutert. Für die Verbindung bietet JDBC-API verschiedene Interfaces und Klassen, die in den Packages java.sql und javax.sql definiert sind. Die folgende Übersicht liefert eine stichpunktartige Übersicht der einzelnen Schritte: Abbildung 9: Verbindungsablauf Schritt 1: JDBC-Datenbanktreiber laden Schritt 2: Datenbankverbindung aufbauen Schritt 3: SQL-Anweisungsobjekt erzeugen Schritt 4: SQL-Anweisung ausführen Schritt 5: Ergebnisse auswerten 14 openbook.galileocomputing.de/javainsel9/javainsel_24_003.htm, http://www.schuenemann.name/studium/sim3D/sim3d-kap2.html (jeweils am aufgerufen 07.05.2014) 11 Schritt 6: SQL-Anweisungsobjekt schließen Schritt 7: Datenbankverbindung schließen Schritt 7 ist besonders wichtig, da Datenbankverbindungen relativ schwergewichtig sind und einige Systemressourcen verbrauchen. Aus diesem Grund, sollte man zur Ausführung von SQL-Anweisungen, nicht jedes Mal wieder eine eigene Datenbankverbindung aufbauen, sondern, wenn möglich, eine bereits bestehende Verbindung nutzen. Daher werden die Schritte 4 und 5 in der Regel mehrfach durchlaufen.15 Damit nicht jedes mal eine aufwendige Verbindung zur Datenbank hergestellt werden muss und diese wegen z.B. nur einer Abfrage gleich wieder geschlossen wird, soll ein Connection-Pool Abhilfe schaffen. Der Connection-Pool öffnet einige Verbindungen zur Datenbank und verwaltet die Verbindungen zentral. Benötigt z.B. ein Programm Zugriff auf die Datenbank, wird diese durch den Pool bereitgestellt und als besetzt markiert. Sobald das Programm fertig ist, wird die Verbindung wieder auf "verfügbar" gesetzt. Dadurch lässt sich der Overhead des Auf- und Abbaus von Verbindungen vermeiden. Gerade in größeren Anwendungen finden oftmals diverse Zugriffe durch verschiedene Benutzer in kurzem zeitlichem Abstand statt. Connection Pooling musste früher selbst realisiert werden. Seit JDBC 2.0 wird es durch Klassen des JDKs unterstützt.16 Sehr wichtig ist noch zu erwähnen, dass alle Schritte in einem Try-Catch Block zu implementieren sind, um mögliche Fehler abzufangen und auszuwerten. 15 16 Der Weg zum Java-Profi Seite 780 Der Weg zum Java-Profi Seite 786 12 5 Datenbankzugriff mit JDBC 5.1 Verbindungsaufbau Der folgende Ablauf bleibt in der Regel immer gleich. Vor der Einführung von JDBC 4 musste man als erstes den Datenbanktreiber laden. Dieser Vorgang ist jetzt nicht mehr notwendig, wurde aber der Vollständigkeit halber gelassen. Diese Aufgabe übernimmt jetzt der DriverManager. Als nächstes baut man mit Hilfe des DriverManagers eine Verbindung zur Datenbank auf und führt die Methode "getConnection()" mit den erforderlichen Parametern aus. Sobald eine Verbindung zur Datenbank hergestellt ist, kann man die gewünschten SQL-Befehle an die Datenbank senden. Wichtig zu erwähnen ist, dass verschiedene Datenbanken verschiedene URL Formate benutzen. DBMS URL Derby jdbc:derby:net://servername:port/ HSQLDB jdbc:hsqldb:hsql://servername:port/database MySQL jdbc:mysql://servername:port/database Oracle jdbc:oracle:thin:@host:port:database Tabelle 1: Datenbank-URLs17 17 Der Weg zum Java-Profi Seite 781 13 Listing 1: Verbindungsaufbau zur Datenbank Da man in Listing 1 einen MySQL-Server nutzt, benötigt man den MySQL URLTypen verwenden. 5.2 Übermitteln von Abfragen Eine Möglichkeit für das übermitteln von Abfragen ist das Interface "Statement". Man schickt mit der Methode "executeQuery()" eine gewöhnliche Abfrage als String, wie z.B. "SELECT * FROM Filme WHERE Title = 'K-Pax' ", und erhält den gewünschten Wert bzw. Datensatz. 14 Listing 2: Übermittlung der Abfrage Wie Listing 2 zeigt, wird statt einem Ist-Gleich-Zeichen ein "like ' %" title+"%' " verwendet. Das Prozentzeichen sorgt dafür, dass die Datenbank alle Werte, die den übergebenen String enthalten, ausgibt. Wenn man allerdings die Datenbank verändern möchte, muss man die Methode "executeUpdate()" verwenden. Anders als in Listing 2 dargestellt, kann das erhaltene Ergebnis auch entsprechende Objekte speichern und wiedergeben. 18 Listing 3: Update-Methode Allerdings besitzt das Interface "Statement" ein paar Schwachstellen. Die erste ist erstmal, wenn wir eine Liste mit Objekten haben und die gleiche Abfrage immer und immer wiederholen wird die gesamte Abfrage jedes Mal an die Datenbank übermittelt und diese muss den String von neuem auswertet und ausführt. Dies kann sich negativ auf die Performance ausüben. Das nächste Problem ist die Syntax von SQL, diese erkennt die Apostroph als StringVergleichsfunktion, was in Java bekanntlich die Anführungsstriche sind. Angenommen wir haben eine Tabelle Personen und wir wollen alle Personen mit dem Namen O'Connor einsehen, sähe die Abfrage als String wie folgt aus: 18 http://clieber.de/index.php?id=4 (aufgerufen am 20.04.2014) 15 "SELECT * FROM Person WHERE Name = 'O'Connor' ". Die Datenbank erkennt zwar den Befehl, hört aber nach dem O auf, da laut SQLSyntax der String-Begrenzer aufhört. Das Programm würde eine "SQLException", mit dem Fehler "java.sql.SQLException: unexpected token: CONNOR", werfen. Außerdem besteht die Gefahr von SQL-Injection. Mit SQL-Injection wird das Einschleusen potenziell schadhafter SQL-Anweisungen in die Datenbankkommandos einer Applikation genannt und stellt eine weit verbreitete Sicherheitslücke dar. Wenn man diese Gefahr jedoch kennt, kann man sich natürlich auch davor schützen. Um sich vor solchen Angriffen zu schützen sollte man konsequent mit "PreparedStatements" arbeiten.19 Um eine allgemeine Abfrage, die Parameter erwartet, zu erstellen wurde das Interface "PreparedStatement" eingeführt. Genau wie bei Statements wird als erstes ein String mit der SQL-Abfrage an die Datenbank gesendet, welcher wie folgt aussieht: "SELECT * FROM Person WHERE = ?". Allerdings verarbeitet die Datenbank den eingehenden String ein wenig anders. Wie einem gleich auffällt enthält die WHERE-Bedingung ein Fragezeichen, welche als Platzhalter für eingehende Parameter dient. Nun hat die Datenbank quasi eine Vorlage, die sie solange das PreparedStatement nicht geschlossen wurde, beliebig oft aufrufen kann und sie die Anweisung nicht immer neu auswerten muss sondern einfach nur die Parameter einsetzen muss. Listing 4: Update mit PreparedStatement Man kann also sagen dass die "Statement"-Möglichkeit für einzelne primitive Anwendungen und Abfragen, welche nur einmalig vorkommen und sich nicht 19 Der Weg zum Java-Profi Seite 784ff 16 wiederholen. Das Interface "PreparedStatement" ist eher für größere Anwendungen, die eine Mehrfachausführung der gleichen SQL-Anweisungen nutzen, besser geeignet. Man kann natürlich auch nur die "PreparedStatement"-Methode aus Listing 4 nutzen, da sie keine erkennbaren Nachteile aufweist und nur von der Implementierung ein wenig abweicht. 5.3 Ergebnisverwaltung Nachdem wir die SQL-Anweisungen an die Datenbank übermittelt haben, erhalten wir natürlich, sofern keine Exception geworfen wurde, ein Ergebnis welches erstmal als ResultSet-Objekt gespeichert wird. Dieses kann mit Hilfe einer While-Schleife (siehe Listing 2) ausgewertet werden. Bevor man aber die Daten verarbeiten kann, muss die Methode next() mindestens einmal aufgerufen werden, egal wie viele Datensätze das Result enthält. Hier stellt sich nun die Frage "Warum muss man immer zuerst die Methode next() aufrufen?". Die Antwort ist ganz einfach. Ein ResultSet enthält einen Datensatzzeiger (auch Cursor genant) welcher den ausgewählten Datensatz referenziert. Da der Zeiger immer vor den Datensätzen steht, muss dieser einmal bewegt werden. Das hat zur Folge dass der Index nicht bei 0 anfängt, sondern ungewohnter weise bei 1. Das besondere an ResultSet ist nicht das speichern der Datensätze, sondern eher das man die gespeicherten Daten modifizieren kann.20 5.3.1 Konfiguration eines ResultSet Standardmäßig erfolgt die Verarbeitung in sukzessiver Vorwärtsrichtung und kann nicht bearbeitet werden. Die Einstellungen erfolgen nicht über das ResultSet sondern werden im Statement festgelegt, welches wiederum das ResultSet erzeugt: Listing 5: ResultSet einstellen 20 Der Weg zum Java-Profi Seite 792 17 Durch setzen einer entsprechenden Konstante für "resultSetType" wird einem nicht nur next() angeboten, sondern auch eine freie Navigierbarkeit. Dadurch können Datensätze direkt angesprungen werden, aber auch eine rückwärts Navigation wird angeboten. "resultSetConcurrency" ermöglicht einem das verarbeiten der Datensätze. Hier werden einem updateXXX()- und getXXX()-Methoden angeboten, welche immer aufrufbar sind. Was am ResultSet besonders interessant ist, ist die Sensitivität für Änderungen. Während wir die erhaltenen Daten verarbeiten, können andere Benutzer auf die Datenbank zugreifen und Veränderungen vornehmen, die auch unsere Daten betreffen. Also kann es passieren, dass wir in der Zeit wo wir die Daten verarbeiten sich diese ändern könnten und wir so mit alten Datensätzen arbeiten. Wenn das ResultSet sensitiv ist, kann es passieren dass die getXXX()-Methoden andere Werte liefern, verglichen mit den Werten zum Konstruktionszeitpunkt, da sie jegliche Änderungen widerspiegelt. Ist das ResultSet allerdings nicht sensitiv, so bekommt man keine Änderungen mit und arbeitet nur mit den Daten die während des Konstruktionszeitpunktes erstellt wurden. Möglicherweise erhält man veraltete Werte.21 Für die Wahl der Einstellungen stellt ResultSet vorgefertigte Methoden bereit. Für Parameter "resultTypeSet" sind folgende Werte definiert: • ResultSet.TYPE_FORWARD_ONLY: Standardeinstellung und erlaubt nur die Vorwärtsrichtung. Jeder Datensatz kann genau einmal verarbeitet werden. • ResultSet.TYPE_SCROLL_INSENSITIVE: Erlaubt einem beliebige Datensätze anzuspringen, bei Bedarf auch mehrfach. Wenn in der Zwischenzeit in der Datenbank Datensätze geändert wurden, werden diese nicht im ResultSet aktualisiert. • ResultSet.TYPE_SCROLL_SENSITIVE: Bietet ebenfalls eine dynamische Einsicht in die Daten, jedoch werden mögliche Änderungen übernommen. 21 Der Weg zum Java-Profi Seite 793 18 Für den Parameter "resultSetConcurrency" sind folgende Werte zulässig: • Resulst.Set.CONCUR_READ_ONLY: Standardeinstellung und erlaubt dem ResultSet keine Änderungen auf die Datenbank. • Resulst.Set.CONCUR_UPDATABLE: Dem ResultSet wird erlaubt Änderungen zu übernehmen, jedoch mit gewissen Einschränkungen. Sobald die Abfrage Joins oder Aggregats- bzw. Gruppierfunktionen nutzt können die Datensätze nicht mehr zugeordnet werden. Der Grund dafür ist, dass die Ergebnismenge nicht 1:1 auf die Datensätze der Datenbank abbildbar ist.22 5.3.2 Änderung am ResultSet In diesem Abschnitt gehen wir davon aus, dass das ResultSet so eingestellt ist, dass man die Datensätze ändern, welche auch in der Datenbank geändert werden, und zu jeder belieben Position springen können. Listing 6: Aktualisierung eines ResultSet Mit der updateString() Methode lässt sich im momentan angezeigtem Datensatz in der angegebenen Spalte, den Wert ändern. Diese Änderung ist erstmals nur im ResultSet, kann aber mit der Methode updateRow() in die Datenbank übernommen werden. In der Praxis ist die Verarbeitung der Daten, zumindest meistens, wesentlich komplexer und kann zu Fehlern führen oder man die geänderten Daten doch nicht in die Datenbank zu übernehmen. Hierfür hat ResultSet eine Methode, welche die vorgenommenen Änderungen wieder rückgängig macht und den Datenbanksatz wieder in den Ursprungszustand zurücksetzt: cancelRowUpdate(). 22 Der Weg zum Java-Profi Seite 793ff 19 Da wir in der Regel nicht die einzigen sind, die Zugriff auf die Datenbank haben und andere Benutzer in der Zwischenzeit auch Änderungen vornehmen könnten, gibt es die Methode refreshRow(). Wie der Name bereits vermuten lässt, aktualisiert das ResultSet und holt sich erneut die Daten aus der Datenbank. 23 Neben Änderungen einzelner Werte im ResultSet, sind auch andere Möglichkeiten offen. Wie z.B. das hinzufügen (insertRow()) oder auch das löschen (delteRow()) von Datensätzen.24 5.4 Schließen der Verbindungen Um den Datenbankserver zu entlasten und Ressourcen für andere Benutzer freizugeben muss jede erstellte Verbindung auch wieder geschlossen werden. Mithilfe der Methode close() lässt sich dies schnell umsetzen. Normalerweise wird jedes close() in einem eigenem try-catch-block abgearbeitet werden. Dies hat den Vorteil, dass wenn eine close() Methode eine Exception wirft die anderen trotzdem ausgeführt wird. Stellen wir uns vor wir hätten alle drei einem Block und die zweite Methode wirft eine Exception aus, würde die Aufwendige Verbindung zur Datenbank nicht geschlossen werden und würde unnötig Ressourcen belegen.25 Listing 7: Try-Catch Block für jede Verbindung 23 Der Weg zum Java-Profi Seite 795ff Der Weg zum Java-Profi Seite 796 25 Der Weg zum Java-Profi Seite 786 24 20 6 JDBC mit Spring Framework Im letzten Abschnitt wird gezeigt, wie einfach der Zugriff auf JDBC-Abstraktionen mit dem Springframework gestaltet ist. Zunächst müssen wir die Bibliotheken mysqlconnector-java.jar, org.springframework.jdbc.jar und org.springframe- work.transaction.jar26 in das Projekt einbinden. Diese kann man kostenlos im Internet herunterladen. Für diesen Abschnitt wurde ebenfalls ein kleines Programm geschrieben, welches Schülerdaten (Name und Alter) verwaltet. Die Verbindung zur Datenbank erfolgt wie folgt: Als erstes erstellen wir eine xml-Datei mit dem Namen "Beans", diese enthält alle relevanten Daten um sich mit dem SQL Server zu verbinden. "Beans" wird von den Entwicklern standardmäßig gewählt. Hierfür werden weitere Bibliotheken benötigt: antlr-runtime-3.0.1, org.springframework.beans-3.1.0.M2, org.springframe- work.context-3.1.0.M2, org.springframework.core-3.1.0.M227 Listing 8: Beans.xml 26 27 http://www.java2s.com/Code/Jar/o/Downloadorgspringframeworkjdbcjar.htm http://www.tutorialspoint.com/spring/spring_jdbc_example.htm (aufgerufen am 07.05.2014) 21 Das Hauptprogramm holt sich mit folgendem Befehl die Werte und stellt dann eine Verbindung her: Listing 9: Verbindungsaufbau zur Datenbank Einmal eine Vorlage kann diese mit ein paar Änderungen stets überall übernommen werden. Mit dieser Variante lässt sich schnell und einfach eine Verbindung herstellen, ohne sich über Exceptions Gedanken machen zu müssen. Das Spring Framework bietet eine Vielzahl an vorgefertigten Klassen und Interfaces die die Arbeit mit JDBC erleichtern soll. Wie wir in Abschnitt 5 gelernt haben, müssen wir der Datenbank eine SQL Abfrage schicken, erhalten ein Ergebnis, speichern diese in einem ResultSet und werten sie anschließend aus. Außerdem müssen wir jede Abfrage in einem Try-Catch Block festhalten, was den Code in die Länge zieht. Anders beim Spring Framework. Zuerst erstellen wir eine Hilfeklasse namens "StudentMapper" die wie folgt aussieht.28 Listing 10: Datensatz in ein Student-Objekt speichern Diese soll uns beim speichern der Datensatzzeile in ein Student-Objekt helfen. So nun wollen wir alle Schüler aus der Datenbank holen und diese in eine Liste mit Student-Objekt speichern. Nach Listing 2 müssten wir erstmal noch ein Statement erstellen bzw. verbinden, im ResultSet speichern und mit einer While-Schleife in das 28 http://www.javabeat.net/introduction-to-spring-jdbc-framework/ (aufgerufen am 07.05.2014) 22 Objekt speichern. Nicht im Spring Framework, diese bietet eine Methode, die alle diese Aufgaben übernimmt und was noch wichtiger ist, nachdem wir das Ergebnis erhalten wird die Verbindung automatisch wieder getrennt, um Ressourcen für andere Benutzer wieder freizugeben. Das hat den Vorteil, dass man beim Programmieren sich keine Gedanken mehr machen muss, wann und ob die Verbindung getrennt werden sollte und dass man nicht den Try-Catch-Block vergisst. Listing 11: Speichert die Datenbanktabelle Auch das Aktualisieren oder das Abrufen einzelner Datensätze aus der Datenbank ist nun ein Kinderspiel: Listing 12: Datenbank aktualisieren Man kann wie beim PreparedStatement Fragezeichen als Platzhalter nutzen, nur muss man jetzt nicht mehr jeden Platzhalter einzeln ansprechen und den UpdateBefehl starten, es erfolgt nun alles in einer Zeile. Was die Sache auch angenehm macht, ist dass man das Objekt direkt speichern kann und keine While-Schleife hierfür benötigt. Das Spring Framework ist eine super Erfindung welches einem das Leben sehr erleichtert, dennoch sollte man sich für ein besseres Verständnis die Grundzüge von JDBC aneignen und verstehen. 23 7 Fazit Wie beim Mitkommilitonen Herr Topalovic war am Anfang die Freude groß, endlich wieder mit Java zu programmieren und für eine Zeit die Microsoft C-Sharp Welt zu vergessen. Zwar heißt es dass JPA mittlerweile Standard geworden ist, aber wie ich feststellen musste nutzen viele Firmen immer noch JDBC, unter anderem auch mein Arbeitgeber, die Firma Adesso. Zu beginn habe ich erstmal ein kleines Programm geschrieben, welches auf eine Datenbank zugreift, ihren Inhalt ausliest und verändert. Ich war stolz darauf und dachte mir dass es so passt und gut zu erlernen ist. Anfangs habe ich das Spring Framework skeptisch betrachtet, ich denke dass die Redensart "Was der Bauer nicht kennt, frisst er nicht " hier zutreffend ist, und dachte mir dass ich es nicht hernehmen werde. Falsch gedacht! Ich hätte nie gedacht, dass das Spring Framework so viele Erleichterungen mit sich bringt. Ich habe zwar nur an der Oberfläche gekratzt. Durch das Fach Software Engineering, wo wir mit C-Sharp programmieren, hatte ich etwas Erfahrung mit dem verwalten und auslesen von Datenbankdaten sammeln können. Ich muss sagen dass mir die Variante von Java um einiges besser gefällt und wenn ich in Zukunft vor der Wahl stünde, würde ich Java JDBC mit dem Spring Framework benutzen. 8 Literaturverzeichnis Michael Inden (2010). Der Weg zum Java-Profi - Konzepte und Techniken für die professionelle Java-Entwicklung, 2. Auflage. Heidelberg: dpunkt.verlag GmbH Alfons Kemper, André Eickler (2013). Datenbanksystem - Eine Einführung, 9. Auflage. Oldenbourg: Wissenschaftsverlag GmbH Christof Lieber (2005). Abgerufen am 20.04.2014 von http://clieber.de/index.php?id=4 24 Anonymus (2014). Abgerufen am 22.04.2014 von http://docs.oracle.com/javase/tutorial/jdbc/overview/index.html Christoph Bergmann (1998). Abgerufen am 05.05.2014 von http://www.java.seite.net/jdbc/index.html Anonymus (2014). Abgerufen am 07.05.2014 von http://www.tutorialspoint.com/spring/spring_jdbc_example.htm Anonymus (2013). Abgerufen am 07.05.2014 von http://www.javabeat.net/introduction-to-spring-jdbc-framework/ 25