Java-Objekte mit SQL verheiraten

Werbung
ITMAGAZINE
Java-Objekte mit SQL verheiraten
24. November 2006 - iBatis ermöglicht die Abstraktion von SQL-Datenbanken, ohne dass man auf von Hand
geschriebene SQL-Abfragen verzichten muss. Entwickelt man Applikationen auf modernen objektorientierten Plattformen wie Java, so stellt sich oft die Frage,
wie man Objekte sauber persistiert. Häufig wird man auf den Komfort und die Leistungsfähigkeit, die relationale
Datenbanken unter anderem in bezug auf Abfragen, Transaktionen und Backup bieten, nicht verzichten wollen.
Nun existiert mit JDBC in Java ein standardisiertes Interface zum Zugriff auf relationale Datenbanken. Die
«direkte» Verwendung von JDBC hat jedoch in der Praxis viele Nachteile:
- Java-Code und SQL-Statements sind üblicherweise vermischt oder lassen sich nur schwer voneinander trennen.
- Die Anwendung ist an eine bestimmte Datenbank gebunden.
- Der Zugriff ist wenig elegant und unflexibel, weil die «Welt der Objekte» und die «Welt der Tabellen»
konzeptionell sehr unterschiedlich sind.
- Oft ist eine flexible Konfiguration erforderlich (Transaktionsmanager, Connection Settings, Datenbank), was
mit direkter JDBC-Programmierung schwer zu erreichen ist
Viel Abstraktions-Aufwand
Meist wird daher bei modernen Anwendungen ein objektrelationales (O/R) Mapping-Tool eingesetzt, das die
Verbindung zwischen Objekten, die persistiert werden sollen, und der Datenbank herstellt. Es gibt hier unzählige
Frameworks, beispielsweise Hibernate, Castor, OJB und Toplink. Dennoch sind diese Frameworks nicht uneingeschränkt zu empfehlen. Hibernate & Co. erlauben, detaillierte
Abbildungen von Objekthierarchien auf Tabellen in einer relationalen Datenbank zu definieren. Der Entwickler
arbeitet dann nur mehr auf Objektebene und bekommt sogar eigene Abfragesprachen wie HQL zur Verfügung
gestellt. Die konkreten SQL-Statements, die für den Zugriff benötigt werden, werden vom Framework je nach
verwendeter Datenbank automatisch generiert. Weiter bieten diese Frameworks typischerweise vollen Roundtrip-Support an. So kann man die Mappings in
Java-Annotationen deklarieren und dann die konkreten Mapping-XML-Dateien sowie die Datenbank generieren
lassen.
Diese Abstraktion ist in vielen Fällen sehr nützlich und leistungsfähig, birgt aber auch verschiedene Nachteile
sowie Risiken: Die Verwendung von Frameworks wie Hibernate ist in der Praxis ziemlich komplex, die
Einarbeitungszeit entsprechend hoch. Man muss die Mapping-Definitionen verstehen, die neue Abfragesprache,
die Tools sowie die vielen Konfigurationsmöglichkeiten wie Caching. All dies kann sehr aufwendig sein,
besonders dann, wenn Code-Generierung verwendet wird. Dies ist eigentlich fast immer anzuraten, weil sonst
die Gefahr besteht, dass verschiedene Teile der Anwendung ausser Synchronität geraten. Frameworks wie Hibernate sind daher vor allem in grossen und komplexen Projekten angeraten, wenn auch ein
entsprechender Experte des jeweiligen Frameworks zur Verfügung steht.
Vorteile ohne Nachteile
iBatis hingegen geht einen anderen Weg. Bruce Tate beschreibt es in seinem Buch «Spring Developers
Notebook» so: «iBatis ist ein JDBC unterstützendes Framework, das viele Vorteile von O/R-Mappern bringt, aber
nicht deren Risiken mitbringt.» iBatis ist eigentlich auch kein O/R Mapping Framework, vielmehr werden
anstelle von Tabellen SQL-Statements auf Objekte gemappt. Das heisst, SQL ist ein zentraler Bestandteil von
iBatis-Anwendungen, allerdings werden diese sauber vom Java-Code über XML-Maps getrennt. Dies hat klare Vor- und Nachteile: Einerseits hat man die volle Leistungsfähigkeit von handoptimiertem SQL zur
Verfügung, was bei Hibernate nur «durch die Hintertür» möglich ist. Gleichzeitig ist damit natürlich die Bindung
an eine konkrete Datenbank auch höher, was aber in vielen Anwendungsfällen unproblematisch ist. Das
Unterstützen einer weiteren Datenbank bedeutet, dass neue Mappings erstellt werden müssen, wozu allerdings
kein Eingriff in den Java-Code notwendig ist. Auch Stored Procedures werden besser unterstützt. Bei einem
niedrigeren Grad an Abstraktion macht dieser Zugang das Mapping natürlich wesentlich einfacher.
Karten für SQL
iBatis benötigt eine Konfigurationsdatei (sqlMap-config.xml), in der die wesentlichen Optionen für den
Datenbankzugriff deklariert werden. Dazu gehört die Konfiguration der verwendeten Datenquelle (z.B. ein
Connection Pool), eines eventuell verwendeten Transaktionsmanagers sowie die Definition der eigentlichen
SQL-Map. Der Kern einer Applikation mit iBatis ist nun die Beschreibung der Mappings (siehe auch Abbildung 1). Im
wesentlichen wird für jedes zu persistierende Objekt eine SQL-Map erstellt. In dieser Map können für dieses
Objekt verschiedene Operationen definiert werden wie «Insert», «Update» oder «Get» Jede dieser Operationen
wird durch ein beliebiges SQL-Statement beschrieben. Das heisst, das Objekt wird an verschiedene
SQL-Statements gebunden, und diese entscheiden dann, welche Tabellen für die Abarbeitung verwendet werden. Dies lässt sich am besten mit einem Beispiel illustrieren: Soll das Objekt «Person» (mit nachname, vorname,
email) in die Datenbanktabelle «PERSON» gespeichert werden, so ist ein Mapping zu definieren, das die
Übergabeparameter aus dem Objekt übernimmt und ein INSERTStatement formuliert, das an die Tabelle
angepasst ist. Es könnte etwa so aussehen: INSERT INTO PERSON ( FIRST_NAME, LAST_NAME, EMAIL ) VALUES ( #vorname#, #nachname#, #email# ) Diese Anweisung wird von iBatis als Prepared Statement abgelegt und kann aus dem Java-Code dann einfach
aufgerufen werden: Pers p = new Pers (“Alexander“, “Schatten“, “[email protected]“); sqlMap.insert(“insertPers“, p); Natürlich muss das SQL-Map-Objekt vom iBatis Typ SqlMapClient sein und vorher entsprechend initialisiert
werden. Weiter kann man im Mapping-Dokument auch SQL-Fragmente wiederverwenden, wenn diese in verschiedenen
Statements benötigt werden. In der Verwendung von Übergabe- und Rückgabe-Parameter ist man flexibel: Es
können Java-Primitive verwendet werden, Collections oder eigene Typ-Konverter. So kann man boolsche Werte
beispielsweise auf Strings wie «Ja» und «Nein» abbilden. Abbildung 1: iBatis-Architektur Direkter Zugriff
Neben den genannten Funktionen bietet iBatis weiter eine DAO-Bibliothek an. Diese ist optional und muss nicht
verwendet werden. Jedoch empfiehlt es sich in jedem Fall, das DAO-Enterprise-Pattern für eigene Anwendungen
einzusetzen – egal, ob man nun die iBatis-Bibliothek verwendet oder es selber implementiert. Der Grundgedanke des DAO-Pattern ist in Abbildung 2 illustriert. Wesentlich ist hier, dass Zugriff auf
Persistenz-Mechanismen nur von ausgewählten Klassen, den DAOs, erfolgt und nicht quer über die Anwendung
verteilt mit Persistenz-Klassen wie den SQL-Maps interagiert wird. Praktisch bedeutet dies folgendes:
- Man definiert ein Interface, in dem in neutraler Weise Zugriffsmethoden definiert sind; diese sind unabhängig
vom verwendeten Persistenz-Mechanismus.
- Man implementiert konkrete DAOs, beispielsweise für iBatis, für XML oder für Hibernate, je nachdem, was
benötigt wird.
- In den «Geschäftsobjekten» arbeitet man ausschliesslich mit Variablen vom Interface-Typ und holt sich die
konkrete DAO-Instanz von einem Container wie Spring.
- Ein Transfer-Objekt (ein normales Java-Bean) wird verwendet, um Daten auszutauschen.
Der grosse Vorteil dieses Ansatzes ist es, dass jederzeit der Persistenz-Mechanismus ausgetauscht werden kann
– von iBatis auf XML oder auf Hibernate –, ohne dass die Business-Logik verändert werden muss: Man muss
«nur» neue DAOs implementieren und die Konfiguration des Containers ändern. Abbildung 2: Aufbau des DAO-Patterns Einsteigen und losfahren
Der Einstieg in iBatis sollte nicht allzu schwerfallen. Einerseits, weil das Konzept leicht verständlich ist,
andererseits aber auch, weil die Dokumentation sehr gut ist. Es existieren ein kurzes Tutorial, das auf wenigen Seiten die Prinzipien mit Code-Beispielen erklärt, ein
umfangreicheres Handbuch sowie eine Beschreibung der Data-Access-Object-Bibliothek. Parallel dazu gibt es
umfangreiche Sekundärliteratur wie «iBatis in Action» (ISBN 1-93239-482-6) oder «Spring, a Developer’s
Notebook» (ISBN 0-596-00910-0) von Bruce Tate. iBatis wird weiter (ebenso wie Hibernate, Castor und OJB) vom Framework Spring unterstützt, das heisst, man
kann sehr einfach die bekannten Spring-Mechanismen zur Konfiguration (Dependency Injection) sowie
deklarative Transaktionen und Templates nutzen. Neben Java existieren auch Portierungen für .Net und Ruby. Spezifische Datenbank-Klassen sind nicht
erforderlich, da ja beliebige JDBC-Treiber sowie SQL-Statements verwendet werden können. Daher sollte iBatis
mit allen bekannten relationalen Datenbanken funktionieren.
Wann iBatis einsetzen?
iBatis ist empfehlenswert, wenn: · volle O/R-Funktionalität nicht unbedingt erforderlich ist und man ein sehr schnell zu erlernendes und dennoch
leistungsfähiges Framework verwenden möchte. · bestehende Datenbanken integriert werden sollen. · Datenbank- und Anwendungsentwicklung getrennt sind. · volle Leistungsfähigkeit von optimierten SQL-Statements genutzt werden soll. · das Datenmodell eher einfach ist. · kein gut geschulter Hibernate-Experte vor Ort ist. iBatis ist hingegen weniger geeignet, wenn: · das Datenmodell komplex ist (Vererbungen etc.) · von SQL abstrahiert werden soll (einfache Unterstützung verschiedener Datenbanken) · Erstellen von Datenbank-Metadaten und Mappings automatisiert werden soll (Codegenerierung)
Der Autor
Alexander Schatten ([email protected]) ist Assistent am Institut für Softwaretechnik und Interaktive
Systeme der Technischen Universität Wien.
Copyright by Swiss IT Media 2017 
Herunterladen