Wirtschaftsinformatik: Komplexe Datenbank-Anwendungen

Sie sind hier: StartseiteWirtschaftsinformatikKomplexe Datenbank-Anwendungen (Persistenz)

IC / CM, Kurs vom 01.10.2005 - 31.03.2006

Komplexe Datenbank-Anwendungen (Persistenz): Persistenz-Konzepte (Betrachtungsdimensionen, Objektorientiertheit, Transparenz, Funktionen eines Persistenz-Rahmenwerks, Ressourcen-Management, Persistenzaspekte, Persistenzstrategien), Persistenz-Implementierung (Strukturierung der Programme, Table Data Gateway, Row Data Gateway, Active Record, Data Mapper, Datenzugriffsmuster, Datenzugriffsobjekte), Objekt-relationale Abbildung (Abbildung von objekt-orientierten Strukturen auf Tabellen, Transformation von Klassen, Transformation von Assoziationen, Transformation von Kompositionen, Transformation von Vererbungen), Umsetzung in Hibernate (Hibernate und Persistenz, Persistenz-Lebenszyklus für Objekte, Unidirektionale Beziehungen, Bidirektionale Beziehungen)

  1. Persistenz (Konzepte)
  2. Persistenz (Implementierung)
  3. Objekt-relationale Abbildung
  4. Umsetzung in Hibernate

Persistenz (Konzepte)

Betrachtungsdimensionen

Persistenz ist die dauerhafte Speicherung von Daten über die Ausführungszeit von Programmen hinaus. In betriebswirtschaftlichen Anwendungen wird dies üblicherweise in Datenbanksystemen realisiert.

Zu unterscheiden sind drei Betrachtungsdimensionen:

Relationale Datenbanksysteme, vorherrschende Technologie im betriebswirtschaftlichen Bereich, sind eine ausgereifte Technologie, die auf Tabellenstrukturen basiert. Wegen ihrer einfachen Strukturen ist eine gute Verständlichkeit garantiert. Wenn für die Programmierung eine objektorientierte Programmiersprache eingesetzt wird, stellt sich jedoch die Frage, wie objekt-orientierte Strukturen auf Tabellenstrukturen abgebildet werden.

Objektrelationale Datenbanksysteme sind eine Erweiterung relationaler Datenbanksysteme um objektorientierte Strukturen und verringern die gerade beschriebene Konzeptlücke. Bisher ist jedoch noch kein verstärkter Einsatz dieser Erweiterungen erkennbar.

Objektorientierte Datenbanksysteme basieren auf objektorientierten Strukturen und weisen daher nur eine geringe bis keine Konzeptlücke zu objektorientierten Programmen auf. Sie waren in den 90er Jahren ein vielbeachtetes Thema, haben sich aber nicht durchgesetzt und führen jetzt ein Nischendasein.

XML-Datenbanksysteme sind eine relativ neue Technologie, die auf XML-Strukturen basiert. Sie weisen keine Konzeptlücke auf, wenn die Anwendung ebenfalls auf XML-Strukturen basiert. Die Konzeptlücke zu objektorientierten Programmen ist geringer als bei relationalen Strukturen. Diese Technologie ist besonders für semi-strukturierte bis unstrukturierte Daten (z.B. Texte) geeignet.

Hierarchische- und Netzwerkdatenbanksysteme sind alte Technologien, vorwiegend in Großrechnersystemen. Viele geschäftskritische Daten wurden in solchen Systemen gespeichert, daher sind solche Systeme in der Praxis häufig anzutreffen. Sie weisen eine große Konzeptlücke zu objektorientierten Programmen auf und werden deshalb immer mehr durch relationale Systeme ersetzt.

Objektorientiertheit

Die Verwendung einer objektorientierten Programmiersprache bestimmt nicht die Objektorientiertheit des Programms. Diese hängt von den im Programm tatsächlich verwendeten Strukturen ab.

Im geringsten Grad der Objektorientiertheit liefert die Datenbank Satzmengen an das Programm zurück, die als solche im Programm weiterverwendet werden.

In einem zweiten Schritt liefert die Datenbank Datensätze in Form von Objekten zurück (Datentransferobjekte). Diese Objekte entsprechen aber 1:1 den Datenbankstrukturen, sind nur Behälter für Daten und haben kein Verhalten (Methoden).

Geschäftsobjekte, höchster Grad der Objektorientiertheit, beinhalten fachliche Logik und entsprechendes Verhalten, basieren auf Strukturen wie Vererbung und Assoziation und erfordern komplexe Transformationen der zugrunde liegenden Datenbankstrukturen (z.B. objektrelationale Abbildung). Sie sind in zwei Arten unterteilbar: Domänen-Objekte stellen Konzepte aus der fachlichen Logik dar (z.B. Kunde, Rechnung, Bestellung). Diese Objekte haben einen Zustand und ein Verhalten, d.h. sie haben Attribute auf die zugegriffen werden kann und Methoden, die auf das fachliche Konzept abgestimmte Funktionalität bereitstellen. Dienst-Objekte beschreiben Abläufe, (z.B. Buchung einer Reise inklusive Hotel- und Flugbuchung), bilden oft eine Fassade für Domänen-Objekte und dienen häufig zur Transaktionsbegrenzung, d.h. eine Methode des Dienstobjekts entspricht einer Transaktion.

Transparenz

Transparenz bezeichnet den Umfang an Operationen zur Speicherbehandlung, die im Programm explizit aufgerufen werden müssen. Das betrifft vor allem zwei Aspekte: Das Laden von Daten und Überführen in programminterne Strukturen sowie das Rückschreiben geänderter programminterner Strukturen in die Datenbank. Beispiel: Das Programm arbeitet mit Objekten für Bestellungen, die jeweils eine Liste von Bestellpositionen beinhalten und eine Referenz auf einen Kunden haben. Gespeichert werden die Daten in einer relationalen Datenbank. Auszuführende Funktionen sind das Laden einer Bestellung, das Ändern einer Bestellposition, z.B. die Bestellmenge, oder das Hinzufügen einer Bestellposition.

Keine Transparenz herrscht vor, wenn das Programm per SQL explizit auf die Tabellen für Bestellungen, Kunden und Bestellpositionen zugreifen muss, um ein Bestellobjekt zu erzeugen. Es muss sich die geänderte Bestellposition merken und spätestens vor Transaktionsende per SQL-Befehl (update) die Änderung speichern. Es muss sich die eingefügte Bestellposition merken und spätestens vor Transaktionsende per SQL-Befehl (insert) die neue Position speichern.

Führt das Programm nur einen Befehl zum Laden des Bestellobjekts aus, liegt komplette Transparenz vor. Die notwendigen Daten zum Kunden und zu den Bestellpositionen werden automatisch aus der Datenbank geholt. Das Programm führt nur einen erfolgreichen Transaktionsabschluss durch (commit); alle Änderungen werden automatisch gespeichert.

Transparenz wird durch Persistenz-Rahmenwerke (Persistence Frameworks) realisiert. Hierbei sind verschiedene Grade zwischen keiner und kompletter Transparenz möglich. Persistenz-Rahmenwerke stellen Schnittstellen und Implementierungen für die Speicherung von Daten zur Verfügung. Sie sollten nicht selbst entwickelt werden (komplex, hoher Arbeitsaufwand, viele Fehlermöglichkeiten; bindet Ressourcen, die für die Anwendungsentwicklung fehlen). Sie sollten einfach in der Benutzung sein, da es sonst trotz guter Funktionalität an Akzeptanz fehlt. Wesentlich ist das Programmiermodell. Die Integration erfolgt z.B. in Applikationsserver oder andere Umgebungen. Persistenz sollte jedoch nicht an eine spezielle Umgebung gebunden werden. Bekannte Rahmenwerke (Auswahl) sind Spring JDBC, Hibernate und EJB.

Funktionen eines Persistenz-Rahmenwerks

Das Laden von Objekten erfolgt über die Navigation im Objektgraph (ausgehend von geladenen Objekten über Referenzen erreichbare Objekte laden), über Identifikatoren (identifier), über eine objekt-orientierte Abfragesprache oder über eine native Abfragesprache (z.B. SQL).

Es gibt verschiedene Ladestrategien für assoziierte Objekte (fetching strategies): immediate fetching (sequenzieller Datenbankzugriff), lazy fetching (Nachladen assoziierter Objekte bei Bedarf), eager fetching (zusammengefasstes Laden von Objekt und assoziierten Objekten mit Verbundoperationen) und batch fetching (gleichzeitiges Laden zusätzlicher Objekte, die möglicherweise in Folgeoperationen benötigt werden).

Das Speichern von Objekten erfolgt explizit durch den Aufruf von Speicherfunktionen oder implizit durch die automatische Erkennung von Änderungen (dirty management). Zu unterscheiden sind zwei Speicherstrategien: Bei Speicherstrategien für assoziierte Objekte (persistence by reachability) garantiert die Kaskadierung von Speicherfunktionen auf assoziierte Objekte eine referenzielle Integrität. Die explizite Definition von Kaskadierungen ist anpassbar an den jeweiligen Zweck. Mit Speicherstrategien für bidirektionale Beziehungen werden bidirektionale Beziehungen in Programmen durch zwei unidirektionale Referenzen abgebildet. Es wird definiert, welche unidirektionalen Referenzen zusammen eine bidirektionale Beziehung bilden und es erfolgt eine Klärung, welche Seite für die Speicherung zuständig ist und welche die inverse Seite ist.

Weitere Funktionen eines Persistenz-Rahmenwerkes sind die Zustandsverwaltung von Objekten (mögliche Zustände: transient, persistent, abgekoppelt), die Identifikation von Objekten (automatische Schlüsselerzeugung auf unterschiedlichen Wegen), die Beziehungsverwaltung (Kardinalitäten, uni- versus bidirektionale Beziehungen), eine objektorientierte Abfragesprache (Mächtigkeit), Transaktionen (lokale versus globale Transaktionen) und das Caching (Objekte, die sich selten ändern, Referenzdaten, Clustering).

Ressourcen-Management

Innerhalb von Programmen muss ein Zugriff auf die zugrunde liegenden Ressourcen erfolgen, üblicherweise auf Datenbanksysteme (Ressourcen-Management). Zwei Arten von Objekten spielen eine Rolle: Fabriken zur Erzeugung von Verbindungen und Verbindungen.

Eine Fabrik zur Erzeugung von Verbindungen repräsentiert den Datenspeicher und erzeugt und verwaltet Verbindungen (Beispiele: DriverManger in JDBC, SessionFactory in Hibernate). Fabriken sind häufig schwergewichtig, d.h. aufwändig in der Erzeugung.

Eine Verbindung repräsentiert eine Kommunikationssitzung mit dem Datenspeicher und ist häufig leichtgewichtig, d.h. kann ohne großen Aufwand erzeugt und wieder geschlossen werden (Beispiele: Connection in JDBC, Session in Hibernate).

Persistenzaspekte

Es gilt verschiedene Persistenzaspekte zu beachten: Einerseits der Umgang mit verschiedenen DB-Systemen (nicht kompatible SQL-Dialekte trotz Standardisierung, unterschiedliches transaktionales Verhalten, Optimierungen), andererseits vorhandene Anwendungen (Legacy Systems: das Datenmodell ist vorhanden und die Anwendung muss sich an dieses anpassen).

Und schlussendlich die Arbeitsaufteilung zwischen DB-System und Programmtechnologie. Das DB-System sollte das machen, was es am besten kann. Das sollte es auf natürlichem Wege tun. Keine Reimplementierung von Datenbankfunktionaltiät in Programmen, z.B. Verbunde, Sperren.

Persistenzstrategien

Eine Persistenzstrategie ist durch eine Auswahl in Bezug auf die Dimensionen Technologie, Objektorientiertheit und Transparenz gegeben. Beispiele: Relationale Datenbank, Satzmengen, keine Transparenz (SQL-basierter klassischer Ansatz, häufig anzutreffen), Relationale Datenbank, Datentransferobjekte, teilweise Transparenz (im Zusammenhang mit EJB 1 und 2 anzutreffen), Relationale Datenbank, Geschäftsobjekte, komplette Transparenz (Ansatz auf Grundlage objekt-relationaler Abbildung, immer häufiger anzutreffen), Objektorientierte Datenbank, Geschäftsobjekte, komplette Transparenz (führt ein Nischendasein), XML-Datenbank, Geschäftsobjekte, keine Transparenz (Ansatz auf Grundlage von XML-Datenbindungen).

Charakteristisch für den SQL-basierten Ansatz sind SQL-Anweisungen zum Lesen und Schreiben von Objekten, eventuell der Einsatz von gespeicherten Prozeduren und dieser Ansatz ist im Allgemeinen nicht transparent. Damit ist kein Werkzeug für die objekt-relationale Abbildung notwendig, es können die Spezifika des jeweiligen SQL-Dialekts genutzt werden (Optimierung) und es ist ein einfacher Zugang zur mengenorientierten Verarbeitung. Allerdings ist das Schreiben und Warten des SQL-Codes arbeitsaufwändig und macht einen erheblichen Teil des Anwendung-Codes aus. Auch der Änderungsaufwand kann erheblich sein (z.B. neue Felder). Einsatzfelder für den SQL-basierten Ansatz sind Anwendungen, die im Wesentlichen eine Sicht auf die vorhandenen Tabellen darstellen, die direkte Manipulation der Tabellendaten, wenn Objektorientierung keine Vorteile bringt, wenn eine mengenorientierte Arbeitweise vorherrschend ist (Berichte, batch updates) oder wenn ein exotisches Datenmodell vorliegt.

Die Objekt-relationale Abbildung ist eine Abbildungsebene zwischen Klassen und Tabellen auf Basis von Metadaten (XML, Annotationen usw.). Sie ist im Allgemeinen transparent, wobei der Grad der Komplettheit variieren kann. Vorteilhaft ist die erhebliche Reduktion des Codes, die Steigerung der Produktivität und die einfachere Wartung. Es fördert ein objekt-orientiertes Denken und die Generierung Datenbank-spezifischen Codes vereinfacht die Migration auf ein anderes DB-System erheblich. Allerdings gibt es keine volle Kontrolle mehr über den Speicherungsprozess, Anfrageoptimierungen sind nicht mehr so einfach möglich und es ist nicht so gut für mengenorientierte Operationen geeignet. Einsatzfelder der Objekt-relationalen Abbildung sind Geschäftsobjekte mit komplexer fachlicher Logik, die Konzentration auf einzelne Objekte (Load-, Edit-, Store-Zyklus), wenn das Datenmodell zur objekt-orientierten Sichtweise passt oder das Caching von Objekten nutzbringend eingesetzt werden kann.

Zum Menü Wirtschaftsinformatik | Zum Seitenanfang

Persistenz (Implementierung)

Strukturierung der Programme

Innerhalb eines Programms wird Code für die fachliche Logik (Geschäftslogik) und zur Umsetzung der Persistenz benötigt. Es stellt sich die Frage nach Aufteilung dieser Code-Arten, d.h. nach der Strukturierung der Programme. Hierzu gibt es verschiedene Alternativen, die jeweils in bestimmten Situationen vorteilhaft sind und nachfolgend beschrieben werden.

Bei der unstrukturierten Mischung von Geschäftslogik und Persistenz-Code wird innerhalb der Implementierung Code zur Umsetzung der Geschäftslogik beliebig mit Code zum Laden und Speichern von Objekten/Daten gemischt. Typisches Beispiel sind Web-Anwendungen auf Grundlage von Skriptsprachen (PHP, MySQL). Sie sind schlecht wartbar, da Änderungen auf Ebene der Datenbank an beliebigen Stellen im Programm nachgeführt werden müssen. Das Programm ist schlecht verständlich, da die Geschäftslogik nur schwer hinter den Details für die Speicherung der Daten erkannt werden kann. Und es ist schlecht testbar, da Geschäftslogik und Persistenz nicht getrennt getestet werden können.

Table Data Gateway

Table Data Gateway (nach Fowler) ist ein Objekt, das als Kapsel für eine gesamte Tabelle dient. Es beinhaltet sämtlichen SQL-Code zum Zugriff auf alle Zeilen der Tabelle und bietet nach außen eine Schnittstelle an, mit der Daten gelesen und geändert werden können. Lesefunktionen liefern Satzmengen an den Aufrufer zurück. Dieses Objekt liefert eine tabellenorientierte Sicht auf die Daten, d.h. keine echte objekt-orientierte Sicht, aber immerhin eine Code-Verbesserung.

Beispiel: PersonTableGateway mit find(id): RecordSet, findWithLastName(String): RecordSet, update(id, lastName, firstName, numberOfDependents), insert(id, lastName, firstName, numberOfDependents) und delete(id).

Row Data Gateway

Row Data Gateway (nach Fowler) ist ein Objekt, das als Kapsel für eine Zeile dient und sämtlichen SQL-Code zum Zugriff auf die Zeile beinhaltet. Zum Auffinden von Daten-Transfer-Objekten (DTOs) wird ein weiteres Objekt benötigt. Diese Struktur ist nicht sehr transparent, da z.B. update explizit erfolgen muss. Es liefert jedoch eine stärker objekt-orientierte Sicht auf die Daten, da ein Gateway-Objekt in einem gewissen Maß ein Domänen-Objekt repräsentiert.

Beispiel: PersonFinder mit find(id): PersonGateway und findWithLastName(String): List<PersonGateway> zeigt auf PersonGateway mit den Attributen lastName, firstName sowie numberOfDependents und den Methoden insert, update und delete.

Active Record

Active Record (nach Fowler) ist wie das Row Data Gateway, enthält allerdings weitere Geschäftslogik und verzeichnet somit eine weitere Steigerung der Objekt-Orientiertheit.

Beispiel: PersonFinder mit find(id): Person und findWithLastName(String): List<Person> zeigt auf Person mit den Attributen lastName, firstName sowie numberOfDependents, den Methoden insert, update und delete sowie den weiteren Methoden getExemtion(), isFlaggedForAudit() und getTaxableEarnings().

Data Mapper

Data Mapper (nach Fowler) ist ein Objekt, das eine Abbildung zwischen Datenbankstrukturen und Programmstrukturen vornimmt (objekt-relationale Abbildung). So sind komplexe Transformationen möglich, die Ergebnis-Klassen enthalten keinerlei Persistenz-Code mehr und echte Domänen-Objekte oder Daten-Transfer-Objekte, die nur Datenbehälter sind, können erzeugt werden.

Beispiel: PersonMapper mit den Methoden insert, update, delete und select zeigt einerseits auf die Datenbank und andererseits auf Person mit den Attributen lastName, firstName, numberOfDependents und den Methoden getExemtion(), isFlaggedForAudit() und getTaxableEarnings().

Datenzugriffsmuster

Das Datenzugriffsmuster (DAO-Muster) ist ein allgemeines Muster zu Abstraktion von Speicherungsfunktionen durch Datenzugriffsobjekte (DAOs).

Die Realisierung ist beispielsweise möglich durch Table Data Gateway (das statt Satzmengen Listen von DTOs zurückliefert) oder Data Mapper (der Domänen-Objekte oder DTOs zurückliefert).

Die programmtechnische Umsetzung erfolgt durch eine Schnittstelle zur Definition der Funktionalität oder durch Implementierung(en) der Schnittstelle.

Datenzugriffsobjekte

Datenzugriffsobjekte (DAOs) sind unabhängig von Persistenzstrategien, d.h. sie können sowohl transparente als auch nicht-transparente Persistenz anbieten. Sie können im Rahmen von Transaktionen eingesetzt werden ohne diese jedoch selbst zu steuern.

Datenzugriffsobjekte enthalten Methoden zum Anlegen, Laden, Suchen und Löschen von Objekten sowie Methoden zum Speichern von Änderungen im Falle nicht-transparenter Persistenz.

DAOs transformieren speichertechnik-spezifische Ausnahmen (z.B. SQLException) in speichertechnik-neutrale Ausnahmen. Ebenso können sie Aggregationsfunktionen bereitstellen.

Der Vorteil bei speichertechnik-neutralen Ausnahmen ist, dass Nutzer eines DAO nicht mehr mit den Ausnahmen der jeweiligen Speichertechniken (z.B. SQLException) arbeiten, sondern statt dessen mit inhaltlich aussagekräftigen Ausnahmen. Beispiele aus der DAO-Unterstützung des Spring-Rahmenwerks sind DataAccessException, DataAccessResourceFailureException und UncategorizedDataAccessException.

DAOs müssen an Transaktionen teilnehmen können, steuern sie aber nicht. DAOs vereinfachen das Testen von Anwendungen, da sämtliche Speicheroperationen hierüber kanalisiert werden. Für Testzwecke kann ein einfaches DAO gebaut werden, das die DAO-Schnittstelle implementiert aber z.B. die Daten nur im Hauptspeicher hält. Auf diese Weise kann das Testen erheblich verkürzt werden.

Zum Menü Wirtschaftsinformatik | Zum Seitenanfang

Objekt-relationale Abbildung

Abbildung von objekt-orientierten Strukturen auf Tabellen

Die Objekt-relationale Abbildung ist eine Abbildung von objekt-orientierten Strukturen auf Tabellen.

Das objekt-orientierte Modell enthält reichere Strukturierungsmechanismen als das relationale Modell. Eine Transformation auf struktureller Ebene ist notwendig. Folgende Konzepte müssen transformiert werden: Klassen, komplexe Datentypen, Assoziationen, Kompositionen und Vererbung.

Transformation von Klassen

Bei der Transformation von Klassen werden Klassen zu Tabellen und Attribute zu Spalten. Die Standardvariante: Eine Klasse wird eine Tabelle. Aber es sind auch andere Verhältnisse denkbar: z.B. eine Klasse auf mehrere Tabellen. Standarddatentypen werden auf korrespondierende Typen in der Datenbank abgebildet.

Bei der Umwandlung von Klassen in Tabellen werden die Typen wie folgt umgesetzt: long wird zu bigint, string wird zu varchar, int bleibt int und Identifikationsattribute bekommen generell den Typ bigint.

Komplexe Typen, die keine Korrespondenz im Typsystem der Datenbank haben, müssen gesondert behandelt werden, z.B. durch programmtechnische Transformation. Eine Klasse, die beispielsweise Geldbeträge inklusive Währungsangabe abbildet, wird in der Datenbank durch zwei Attribute (Wert, Währung) gespeichert. Das Attribut initialPrice vom Typ MonetaryAmount wird in der Tabelle zu initialPrice_value: decimal und initialPreis_currency: varchar. Die Transformation erfolgt durch den Programmcode (Transformation von komplexen Attributen).

Transformation von Assoziationen

Bei der Transformation von Assoziationen sind 1:n-Assoziationen (bei Umwandlung der Klassen in Tabellen landet ein Fremdschlüssel auf der n-Seite) und n:m-Assoziationen (Einführung einer Zwischentabelle, die Fremdschlüssel der beiden Seiten enthält) zu unterscheiden.

Es können unidirektionale Beziehungen (eine Klasse enthält eine Referenz auf die andere Klasse, es kennt also nur einer den anderen) und bidirektionale Beziehungen (beide Klassen enthalten jeweils eine Referenz auf die andere Klasse, sie kennen sich also beide) auftreten.

Transformation von Kompositionen

Bei der Transformation von Kompositionen ist zwischen Entity-Typen und Wert-Typen zu unterscheiden.

Entity-Typen haben eine eigene Datenbankidentität sowie einen Lebenszyklus und existieren unabhängig von anderen Entity-Typen. Eine Klasse Nutzer hat beispielsweise Attribute wie Vorname und Nachname.

Wert-Typen haben keine Datenbankidentität, ihre Daten werden in die Daten der besitzenden Entität eingebettet. Außerdem sind Wert-Typen abhängig von anderen Entity-Typen. Jetzt kommt also eine zweite Klasse Adresse ins Spiel, mit Attributen wie Straße, Postleitzahl und Ort. Diese Klasse ist durch die Anweisungen Haus und Rechnung an erstere gebunden. In der entstehenden Gesamttabelle Nutzer werden die Attribute der zweiten Klasse durch diese doppelte Anbindung an Klasse Nutzer zu Haus_Straße, ... sowie Rechnung_Straße.

Transformation von Vererbungen

Bei der Transformation von Vererbungen gibt es drei Varianten.

Eine Tabelle für die gesamte Klassenhierachie: Ein Beispiel soll die Funktionsweise verdeutlichen. Klasse Bankkonto und Klasse Kreditkarte sind von Klasse Gebühren abgeleitet. Die entstehende Tabelle nimmt einfach alle Attribute aller Klassen auf. Vorteile: einfache Struktur, keine Verbundoperationen notwendig, polymorphe Beziehungen und Abfragen möglich. Nachteile: Datenkonsistenz schwieriger zu gewährleisten, da Spalten aus den abgeleiteten Klassen keine not null Beschränkung haben können.

Eine Tabelle pro Unterklasse: Gleiche Klassen wie gerade. Jetzt werden jedoch auch drei Tabellen erstellt. Die Tabellen, die aus den abgeleiteten Klassen entstehen, erhalten jeweils noch ein Identifikationsattribut. Vorteile: polymorphe Beziehungen und Abfragen möglich, Datenkonsistenz in Bezug auf not null-Spalten bleibt erhalten. Nachteile: Verbundoperationen notwendig.

Eine Tabelle pro konkreter Unterklasse: Wir bleiben bei den oben beschriebenen Klassen. Die abgeleiteten Klassen werden zu Tabellen, werden jeweils um ein Identifikationsattribut ergänzt und enthalten zusätzlich jeweils die geerbten Attribute. Vorteile: Datenkonsistenz in Bezug auf not null-Spalten bleibt erhalten, keine Verbundoperationen notwendig. Nachteile: Polymorphe Beziehungen und Abfragen nicht möglich.

Eine polymorhe Beziehung ist die Beziehung zu einer Klasse, die wiederum Unterklassen hat.

Zum Menü Wirtschaftsinformatik | Zum Seitenanfang

Umsetzung in Hibernate

Hibernate und Persistenz

Hibernate unterstützt die Persistenz für Java-Objekte durch ein einfaches Komponentenmodell (POJOs). Die Transformation von Objektorientiertheit-Konzepten erfolgt durch Klassen und komplexe Datentypen sowie Assoziationen, Kompositionen und Vererbung. Aus Funktionalität-Sicht bietet Hibernate das Laden von Objekten, Ladestrategien für Assoziationen, Dirty-Management, Speichern von Objekten, Speicherstrategien für Assoziationen, Persistence by Reachability, Beziehungsverwaltung, Zustandsverwaltung und Identifikation von Objekten, objektorientierte Abfragesprache, Transaktionen und Caching.

Hibernate bietet Transparenz durch objekt-relationale Abbildung (OR-Mapping). Java-Klassen, Tabellen und OR-Abbildung (Metainformation, z.B. in XML) sind über einen OR-Abbilder verknüpft.

Persistenz-Lebenszyklus für Objekte

Betrachten wir nun den Persistenz-Lebenszyklus für Objekte. Objekte können die Zustände transient (englisch für "vorübergehend"), persistent (englisch für "hartnäckig") und detached (englisch für "abgekoppelt") annehmen.

Der Lebenszyklus beginnt mit der Anweisung get(), load() oder find(), womit gleich auf ein persistentes Objekt zugegriffen wird. Wird zuerst jedoch ein neues Objekt erzeugt, ist es transient. Es kann nun direkt wieder weggeschmissen werden (garbage) oder aber weiter verarbeitet werden. Durch Aktionen wie save() oder saveOrUpdate findet ein Zustandswechsel statt, das Objekt befindet sich dann im Zustand persistent. Wird ein persistentes Objekt durch delete() gelöscht, nimmt es wieder den transienten Zustand an.

Doch bleiben wir vorerst im persistenten Zustand. Durch Aktionen wie evict(), close() oder clear() geht das persistente Objekt in den Zustand detached über. Es wurde somit aus der Session entfernt, verliert seine Identität jedoch nicht und kann dadurch natürlich auch wieder persistent gemacht werden. Es kann also durch Aktionen wie update(), saveOrUpdate() oder lock() wieder in den Zustand persistent überführt werden. Es kann jedoch auch aus dem detached-Zustand heraus im garbage-Collector landen und damit Lebenszyklus beendet werden.

Unidirektionale Beziehungen

Eine unidirektionale 1:n-Beziehung wird in Hibernate durch das Einfügen des Attributes fetch="..." auf der "ich-kenne-den-anderen"-Seite (<many-to-one name="item" class="de.fhtwberlin.biditem1.Item" fetch="...">) und auf der ahnungslosen Seite mit der Angabe des Attributes lazy="..." markiert (<class name="Item" table="Item" lazy="...">).

Resultierend aus den verschiedenen Kombinationsmöglichkeiten ergeben sich folgende Ladestrategien: Mit fetch="select" und lazy="true" eine SQL-Anweisung für die kennende Klasse, eine SQL-Anweisung für die gekannte nur bei Bedarf. Mit fetch="select" und lazy="false" eine SQL-Anweisung für die kennende Klasse, eine SQL-Anweisung für die gekannte direkt hinterher. Mit fetch="join" und lazy="true, false" eine SQL-Anweisung für beide Klassen zusammen.

Bidirektionale Beziehungen

Bei einer bidirektionalen 1:n Beziehung muss geregelt werden, welche Seite für die Speicherung der Beziehung zuständig ist. Tatsächlich setzt sich eine bidirektionale Beziehung aus zwei unidirektionalen zusammen, deren Zusammengehörigkeit für das System nicht ersichtlich ist.

Mit inverse="true" wird für eine Seite festgelegt, dass diese als Inverse einer anderen betrachtet wird und damit die andere Seite der Beziehung die Speicherung vornimmt. Das Attribut cascade legt fest, wie Einfügungen, Änderungen und Löschungen kaskadiert werden. Mögliche Werte sind none, save-update, delete, all, all-delete-orphan, delete-orphan.