Mittwoch, 23. Mai 2012


Artikel

Januar 2003 | Artikel

Access-Layer pur

(Link zum Artikel: http://www.entwickler.de/jaxenter//000289)

Open Source-Perlen: Objekt-Persistenz mit Hibernate

Text: von Stefan Edlich
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Im zweiten Teil dieser Serie wird ein auf Sourceforge gehosteter Access-Layer vorgestellt. Hibernate verspricht das schnelle Speichern, Laden und Verändern der Java-Objekte einer Anwendung - ohne Codeänderungen wie bei JDO - und unterstützt eine Vielzahl von Datenbanken. Im Folgenden wird das Tool kurz vorgestellt und damit Anregung zur weiteren Beschäftigung mit diesem Access-Layer gegeben.

Auf der Suche nach geeigneten Möglichkeiten für die Speicherung seiner Objekte kommt man schnell auf die Idee, sich an EJBs, Objektdatenbanken oder neue magische JDO-Technologien zu wenden. Nicht so sehr geläufig ist allerdings die Menge der Mapper wie Toplink, die ohne obige Technologieansätze auskommen. Erst recht, wenn es darum geht, kostenfreie Open Source-Technologien zu verwenden.
Zu der letztgenannten Menge gehören Werkzeuge wie:

  • Hibernate aus Sourceforge [1]
  • dbgen aus Sourceforge [2]
  • JAWS von JBoss [3]
Das hier vorgestellte Hibernate macht einen ausgereiften Eindruck und kommt als 0.7MB große jar-Datei daher. Benötigt werden allerdings einige weitere Bibliotheken wie logging, XML, commons*, etc. Enthalten sind außerdem einige Beispiele, die die Verwendung von Hibernate und den Build-Prozess betreffen. Unterstützt werden nahezu alle gängigen Datenbanken. Intern verwendet Hibernate die Reflection-API und erzeugt dynamisch SQL-Code, um mit den Objekten zu arbeiten.
In fünf Schritten zur Persistenz
Anders als andere clevere Access-Layer oder Frameworks " die in späteren Folgen vorgestellt werden " muss zwischen der Objektdefinition und der Speicherung des Objektes noch ordentlich Hand angelegt werden. Im Folgenden werden die Schritte beschrieben, wenn von Klassen ausgegangen wird aber noch keine mit Schema initialisierte Datenbank vorhanden ist. Die Möglichkeit des Reverse-Engineering aus einem Datenbankschema besteht bei Hibernate natürlich auch, wird aber hier nicht weiter betrachtet.
Schritt 1: Klassendefinition
Klassen, die Hibernate speichern kann, sind normale Java Klassen, bei denen die Membervariablen ruhig privat sein können und getter/setter vorhanden sein müssen. Damit Hibernate nach einem load die gefundene Klasse auch instanziieren kann, muss sie einen leeren Default-Konstruktur haben. Für einige Tools oder cascaded-deletes ist weiterhin eine id nötig, die dem Primärschlüssel der Datenbank entspricht. Alle erbenden Klassen müssen obige Regeln ebenfalls beachten.
Bei Bedarf können die Funktionen onSave(), onUpdate(), onDelete() und onLoad() implementiert werden, um selbst bei Persistenzaktionen Methoden auszuführen.
Schritt 2: Generierung der Mapping-Information
Sind alle Pfade korrekt gesetzt, so kann mit

java cirrus.hibernate.tools.MapGenerator --output=Contact.hbn.xml Contact

die Mapping-Datei generiert werden, die die Member-Variablen auf die Datenbankspalten abpictureet:
  1. ...<property name="version" column="version" type="int"/>
  2. <property name="phone" column="phone" type="string"/>...
Schritt 3: Erzeugung und Ausführung des Datenbankschemas
Da hier von einer leeren Datenbank ausgegangen wird, wird ein Tool benötigt, das dass Schema erstellt und gleich auf der Datenbank ausführt:

java -Dhibernate.dialect=cirrus.hibernate.sql.Datenbankdialekt -Dhibernate.connection.driver_class=datenbanktreiber -Dhibernate.connection.url=connectionURL -Dhibernate.connection.username=username -Dhibernate.connection.password=password cirrus.hibernate.tools.SchemaExport --output=Contact.ddl Contact.hbn.xml

Damit ist die Datenbank initialisiert und Objekte können nun im Java-Code gespeichert werden.
Schritt 4: Erzeugung von Datastore und Session
Im Java-Code ist ein Datastore zu erzeugen, indem die Mapping-Datei oder die Klasse angegeben wird. Auf dieser kann dann eine Session geholt werden, die das Arbeiten mit den Objekten ermöglicht:
  1. ds = Hibernate.createDatastore().storeFile(edlich.Contact);
  2. sf = ds.buildSessionFactory();
  3. se = sf.openSession();
Schritt 5: Schreiben, Suchen, Ändern und Löschen von Objekten
Im Folgenden sind einige Beispiele für Operationen mit Objekten angegeben. Dabei ist c1 genau das Objekt, welches entsprechend der ursprünglichen Klasse instanziiert wurde:

Listing 1
  1. sess.add(c1); // Speichern
  2. //Laden und danach updaten
  3. Contact c2 = (Contact) sess.load(Contact.class, 42);
  4. cat.setName("Mustermann");
  5. sess.flush();
  6. // Löschen eines Objektes
  7. sess.delete(c3);
  8. // Suchen von Teilinformation
  9. String phone = se.find("select phone from Contact in class edlich.Contact where Contact.name = ‚edlich‘");
Er kann aber noch mehr ...
Die hier gezeigten Beispiele haben hoffentlich neugierig gemacht. Selbstverständlich bietet Hibernate viele weitere Möglichkeiten, unter anderem die Folgenden:
  • Hibernate kann mit Collections umgehen und Dinge wie Map, Set oder Lists speichern.
  • Die Query-Language erlaubt umfangreiche Abfragen wie table-joins, Aggregat-Funktionen (sum, avg, min, max, count) oder group by, having, order-by.
  • Verschiedene Beziehungsarten und entsprechende suchen / cascaded deletes sind möglich.
  • Der Datenzugriff ist Threadsave.
  • Es sind diverse Cache-Mechanismen enthalten.
So wurde auch an eine Zusammenarbeit mit J2EE gedacht, wie beispielsweise die Verwendung in Session-Beans / Servlets oder die Angabe von Datasources.
Fazit
Der Overhead, den Hibernate mittels Reflection und durch den generierten SQL Code erzeugt, ist in der Regel gering, daher ist der Code relativ schnell. In wenigen Fällen wünscht man sich dennoch von Hand eingreifen zu können, um Sonderfälle - wie zu langsame Abfragen über joins - zu optimieren.
Bei Tests und im Projekteinsatz für viele Klassen ist es weiterhin wichtig, die Erzeugung der Zwischenschritte (Mapping-Datei erstellen, Schemainformation senden, etc.) aus Zeitgründen zu automatisieren. Die Erstellung der zugehörigen Ant-Tasks kostet auch hier einige Stunden und Nerven, da Beispiele entweder fehlerhaft sind, gänzlich fehlen oder sich schwer übertragen lassen. Eine gute Community sorgt aber auch hier sicherlich für baldige Hilfe.
Den Vergleich zu kommerziellen Profi-Werkzeugen (wie etwa dem Access-Layer aus dem Trend-Framework [4] oder Toplink [5]) muss Hibernate allerdings dennoch scheuen, da z. B. Wizards, Integration in Modellierungswerkzeuge, die Option des Verzichts auf vom Anwender erstellte Mapping-Dateien, Prototypengenerierung und einiges mehr fehlen. Für ein neues Projekt ist weiterhin abzuwägen, ob der Access-Layer auch die vielen Spezialbereiche wie logisches löschen, Versionierung der Objekte oder verschiedene Lockingstrategien - wie hierarchische Sperren auf Objekten - beherrscht.
Ist das Problem der Ant-Generierung von Mapping-Dateien und anderer Handarbeit aber einmal automatisiert, kann Hibernate jedoch für einfache Projekte als Access-Layer durchaus wertvolle Dienste leisten.
Links und Literatur

Kommentare