Konzept: Relationale Datenbanken und Objektorientierung
Dieses Konzept enthält einen Überblick über die Objektmodelle und relationalen Datenmodelle sowie eine zusammenfassende Beschreibung eines Framework für persistente Datenspeicherung.
Beziehungen
Zugehörige Elemente
Hauptbeschreibung

Einführung

Dieses Konzeptdokument enthält einen Überblick über die Objektmodelle und relationalen Datenmodelle sowie eine zusammenfassende Beschreibung eines Framework für persistente Datenspeicherung.

Relationale Datenbanken und Objektorientierung

Relationale Datenbanken und Objektorientierung sind nicht vollständig kompatibel. Sie stellen zwei unterschiedliche Sichten der Welt dar: In einem RDBMS sehen Sie nur Daten, in einem objektorientierten System nur Verhalten. Es ist nicht so, dass eine Perspektive besser ist als die andere. Das objektorientierte Modell eignet sich eher für Systeme mit komplexem und zustandsabhängigem Verhalten, in denen Daten zweitrangig sind, und Systeme, in denen durch Navigation in einer natürlichen Hierarchie (z. B. Teilelisten) auf die Daten zugegriffen wird. Das RDBMS-Modell eignet sich für Berichtsanwendungen und Systeme, in denen die Beziehungen dynamisch oder Ad-hoc sind.

Tatsächlich müssen beide Systeme zusammenarbeiten. In relationalen Datenbanken sind viele Informationen gespeichert. Wenn objektorientierte Anwendungen auf diese Daten zugreifen möchten, müssen Sie in der Lage sein, aus einem RDBMS zu lesen und in ein RDBMS zu schreiben. Außerdem müssen sich objektorientierte Systeme häufig Daten mit nicht objektorientierten Systemen teilen. Deshalb ist es nahe liegend, ein RDBMS als Mechanismus für die gemeinsame Nutzung der Daten einzusetzen.

Obwohl das objektorientierte und das relationale Design einige Gemeinsamkeiten haben (Objekte sind konzeptionell mit Entitäten vergleichbar und Attribute mit Spalten), ist eine nahtlose Integration aufgrund der fundamentalen Unterschiede eine Herausforderung. Der wichtigste Unterschied ist der, dass Datenmodelle Daten (über Spaltenwerte) offen legen und Objektmodelle die Daten hinter ihren öffentlichen Schnittstellen verbergen.

Relationales Datenmodell

Das relationale Modell setzt sich aus Entitäten und Relationen zusammen. Eine Entität kann eine physische Tabelle oder eine logische Projektion mehrerer Tabellen sein. Diese logische Projektion wird auch Sicht genannt. Die folgende Abbildung zeigt die Tabellen POSITION, AUFTRAG und PRODUKT und deren Beziehungen untereinander. Ein relationales Modell hat die folgenden Elemente:

Abbildung ist im Inhalt beschrieben.

Ein relationales Modell

Eine Entität hat Spalten. Jede Spalte hat einen Namen und einen Typ. In der vorherigen Abbildung hat die Entität POSITION die Spalten Positions_Id (der Primärschlüssel), Beschreibung, Preis, Menge, Produkt_Id und Auftrags_Id (die letzten beiden Spalten sind Fremdschlüssel, die die Entität POSITION mit den Entitäten AUFTRAG und PRODUKT verknüpfen).

Eine Entität hat Datensätze oder Zeilen. Jede Zeile enthält eine eindeutige Sammlung von Informationen, die in der Regel die persistenten Daten eines Objekts darstellen. 

Jede Entität hat mindestens einen Primärschlüssel. LineItem_Id ist der Primärschlüssel für LINEITEM.

Die Unterstützung von Relationen ist anbieterspezifisch. Das Beispiel veranschaulicht das logische Modell und die Relation zwischen den Tabellen PRODUKT und POSITION. Im physischen Modell werden Relationen normalerweise mit Fremdschlüssel/Primärschlüssel-Referenzen implementiert. Wenn eine Entität in Relation zu einer anderen steht, enthält sie Spalten, die Fremdschlüssel sind. Fremdschlüsselspalten enthalten Daten, die bestimmte Datensätze in der Entität mit der zugehörigen Entität in Relation setzen können.

Relationen weisen Multiplizität (oder Kardinalität) auf. Gebräuchliche Kardinalitäten sind 1:1, 1:m, (m:1) und m:n. In dem Beispiel hat POSITION eine 1:1-Beziehung zu PRODUKT und PRODUKT eine 0:m-Beziehung zu POSITION.

Objektmodell

Ein Objektmodell enthält unter anderem Klassen (siehe [UML01] für eine vollständige Definition eines Objektmodells). Klassen definieren die Struktur und das Verhalten einer Gruppe von Objekten oder Instanzen. Die Struktur wird in Form von Attributen (Datenwerten) und Assoziationen (Beziehungen zwischen Klassen) dargestellt. Die folgende Abbildung veranschaulicht ein einfaches Klassendiagramm, das nur die Attribute (Daten) der Klassen zeigt.

Abbildung ist im Inhalt beschrieben.

Objektmodell (Klassendiagramm)

Ein Auftrag hat eine Nummer (die Auftragsnummer) und eine Assoziation zu einem oder mehreren (1..*) Positionen. Jede Position hat eine Menge (die bestellte Menge).

Das Objektmodell unterstützt Vererbung. Eine Klasse kann Daten und Verhalten von einer anderen Klasse (z. B. erben die Produkte Softwareprodukt und Hardwareprodukt Attribute und Methoden von der Klasse Produkt).

Frameworks für persistente Datenspeicherung

Die meisten Geschäftsanwendungen setzen relationale Technologie für physische Datenspeicher ein. Entwickler objektorientierter Anwendungen müssen die Herausforderung bewältigen, die relationale Datenbank so zu integrieren, dass Änderungen am Datenmodell sich nicht negativ auf das Objektmodell auswirken und umgekehrt. Es gibt viele Lösungen, mit denen Anwendungen direkt auf relationale Daten zugreifen können. Die Herausforderung ist eine nahtlose Integration von Objektmodell und Datenmodell.

Datenbank-APIs werden in unterschiedlichen Standardausführungen bereitgestellt (z. B. die Microsoft Open Data Base Connectivity API oder ODBC) und sind proprietär (native Bindungen zu bestimmten Datenbanken). Die APIs bieten DML-Pass-Through-Services (Data Manipulation Language, Datenbearbeitungssprache), mit denen Anwendungen direkt auf relationale Daten zugreifen können. In objektorientierten Anwendungen müssen die Daten einer objektrelationalen Übersetzung unterzogen werden, damit sie von der Anwendung verwendet werden können. Hierfür muss ein nicht unerheblicher Teil des Anwendungscodes die Ergebnisse der Datenbank-API in Anwendungsobjekte übersetzen. Das objektrelationale Framework kapselt den physischen Datenspeicher und stellt die entsprechenden Services für die Übersetzung der Daten in Objekte zur Verfügung.

Abbildung ist im Inhalt beschrieben.

Zweck eines Framework für die persistente Datenspeicherung

Anwendungsentwickler verbringen mehr als 30 % ihrer Zeit mit der Implementierung des Zugriffs auf relationale Datenbanken in objektorientierten Anwendungen. Wenn die objektrelationale Schnittstelle nicht ordnungsgemäß implementiert wird, ist die Investition verloren. Die Implementierung eines objektrelationalen Framework sichert diese Investition. Das objektrelationale Framework kann in nachfolgenden Anwendungen wiederverwendet werden, was die Kosten für die objektrelationale Implementierung auf weniger als 10 % der Gesamtimplementierungskosten reduziert. Die wichtigsten Kosten, die bei der Implementierung jedes Systems zu berücksichtigen sind, sind die für die Pflege. Über 60 % der Gesamtkosten eines Systems können auf die gesamte Lebensdauer gesehen der Pflege zugeschrieben werden. Ein schlecht implementiertes objektrelationales System ist sowohl aus technischer als auch aus finanzieller Sicht ein Albtraum.

Relevante Merkmale eines objektrelationalen Framework

  • Leistung. Besondere Aufmerksamkeit muss dem Zerlegen von Objekten in Daten und dem Zusammensetzen von Objekten aus Daten gewidmet werden. In Systemen mit einem hohen und kritischen Datendurchsatz ist dies die Achillesferse einer Zugriffsschicht mit mangelhaftem Design.
  • Designkompromisse minimieren. Ein beliebtes Verfahren der Anhänger der Objektorientierung, die bereits Systeme mit relationalen Datenbanken erstellt haben, besteht darin, das Objektmodell so anzupassen, dass Daten einfacher in relationalen Systemen abgelegt werden können, und das relationale Modell so zu ändern, dass Objekte einfacher gespeichert werden können. Obwohl häufig geringfügige Anpassungen erforderlich sind, minimiert eine sorgfältig entworfene Zugriffsschicht negative Eingriffe in das Design von Objektmodell und relationalem Modell.
  • Erweiterbarkeit. Die Zugriffsschicht ist ein Whitebox-Framework, das Anwendungsentwicklern die Erweiterung des Framework ermöglicht, falls eine bestimmte Funktionalität im Framework gewünscht wird. Normalerweise unterstützt eine Zugriffsschicht ohne Erweiterung 65-85 % der Datenspeicheranforderungen einer Anwendung. Falls die Zugriffsschicht nicht als erweiterbares Framework entworfen ist, kann die Erfüllung letzten 35-15 % sehr schwierig und kostenintensiv sein.
  • Dokumentation. Die Zugriffsschicht ist sowohl eine Blackbox-Komponente als auch ein Whitebox-Framework. Die API der Blackbox-Komponente muss klar definiert, sorgfältig dokumentiert und leicht verständlich sein. Wie bereits erwähnt, ist das Design der Zugriffsschicht auf Erweiterung ausgelegt. Ein erweiterbares Framework muss sehr sorgfältig dokumentiert werden. Klassen, die in Unterklassen aufgeteilt werden sollen, müssen angegeben werden. Die Merkmale der Protokolle aller relevanten Klassen (z. B. öffentlich, privat, geschützt, final...) müssen angegeben werden. Außerdem muss zur Vereinfachung der Erweiterbarkeit ein erheblicher Teil des Designs des Zugriffsschicht-Frameworks veröffentlicht und dokumentiert werden.
  • Unterstützung gebräuchlicher objektrelationaler Zuordnungen. Eine Zugriffsschicht muss verschiedene grundlegende objektrelationale Zuordnungen unterstützen, auch wenn keine Erweiterung erforderlich ist. Diese objektrelationalen Zuordnungen werden in einem späteren Abschnitt dieses Dokuments beschrieben.
  • Persistenzschnittstellen. In einer objektorientierten Anwendung enthält das Geschäftsmodell für eine Objektanwendung das semantische Wissen über die Problemdomäne. Entwickler müssen Objekte bearbeiten und mit Objekten interagieren können, ohne sich zu viel Gedanken über die Details der Datenspeicherung und des Datenabrufs zu machen. Dazu muss den Anwendungsentwicklern eine sorgfältig definierte Untergruppe persistenter Schnittstellen (speichern, löschen, suchen) bereitgestellt werden.

Einheitliche objektrelationale Services

Es werden immer mehr einheitliche Verfahren für objektrelationale Anwendungen entwickelt. IT-Experten, die sich wiederholt durch diese Thematik gekämpft haben, verstehen und erkennen mittlerweile bestimmte Strukturen und Verhalten, die erfolgreiche objektrelationale Anwendungen aufweisen. Diese Strukturen und Verhalten wurden mit den CORBA-Servicespezifikationen auf hoher Ebene formalisiert (die sich gleichermaßen für COM/DCOM-basierte Systeme eignen).

Im Folgenden sind die CORBA-Servicespezifikationen aufgelistet, die in der objektrelationale Zuordnung anwendbar und hilfreich sind:

In den folgenden Abschnitten werden diese Kategorien verwendet, um die Diskussion über einheitliche objektrelationale Services zu strukturieren. Nähere Einzelheiten sollten Sie in den entsprechenden CORBA-Spezifikationen nachlesen.

Persistenz

Persistenz ist ein Begriff, der beschreibt, wie Objekte ein sekundäres Speichermedium verwenden, um ihren Zustand über diskrete Sitzungen hinweg aufrecht zu erhalten. Persistenz bietet einem Benutzer die Möglichkeit, Objekte in einer Sitzung zu speichern und in einer späteren Sitzung erneut auf sie zuzugreifen. Beim späteren Zugriffen haben die Objekte genau denselben Zustand (z. B. Attribute) wie in der vorherigen Sitzung. In Mehrbenutzersystemen ist dies möglicherweise nicht der Fall, da andere Benutzer auf dieselben Objekte zugreifen und diese ändern können. Persistenz steht in Wechselbeziehung zu den anderen in diesem Abschnitt beschriebenen Services. Der Hinweis auf Beziehungen, Parallelität und andere Services ist beabsichtigt (und mit der CORBA-Dekomposition der Services konsistent).

Beispiele für bestimmte Services der Persistenz:

  • Verbindungsmanagement für Datenquellen: Objektrelationale Anwendungen müssen eine Verbindung zur physischen Datenquelle aufbauen. Relationale Datenbanksysteme erfordern in der Regel die Angabe des Servers und der Datenbank. Die Einzelheiten des Verbindungsmanagements sind in der Regel von Datenbanklieferant zu Datenbanklieferant verschieden, und das Framework muss auf entsprechend flexible Weise gestaltet werden.
  • Objektabruf: Wenn Objekte aus einer Datenbank wiederhergestellt werden, werden Daten aus der Datenbank abgerufen und in Objekte übersetzt. Bei diesem Prozess werden Daten aus datenbankspezifischen Strukturen, die von der Datenquelle abgerufen werden, extrahiert. Anschließend werden die Daten von Datenbanktypen in die entsprechenden Objekttypen und/oder Klassen zerlegt, das entsprechende Objekt erstellt und spezielle Objektattribute gesetzt.
  • Objektspeicherung: Der Prozess der Objektspeicherung ist eine Spiegelung des Objektabrufs. Die Werte der entsprechenden Attribute werden aus dem Objekt extrahiert. Anschließend wird eine datenbankspezifische Struktur mit den Attributwerten (eine SQL-Zeichenfolge, eine gespeicherte Prozedur oder ein spezieller Fernprozeduraufruf) erstellt und die Struktur an die Datenbank übergeben.
  • Löschen von Objekten: Wenn Objekte aus einem System gelöscht werden, müssen die zugehörigen Daten aus der relationalen Datenbank gelöscht werden. Beim Löschen eines Objekts müssen entsprechende Informationen aus dem Objekt extrahiert werden. Anschließend muss eine Löschanforderung (eine SQL-Zeichenfolge, eine gespeicherte Prozedur oder ein spezieller Fernprozeduraufruf) erstellt und die Anforderung an die Datenbank übergeben werden. In einigen Sprachen wie Smalltalk und Java wird ein explizites Löschen von Objekten nicht unterstützt. Stattdessen wird eine Strategie mit dem Namen Garbage-Collection unterstützt. Frameworks für die persistente Datenspeicherung, die diese Sprachen unterstützen, müssen eine Alternative bieten, mit der Daten aus der Datenbank entfernt werden können, sobald keine Anwendungen mehr auf die Daten verweisen. Eine gebräuchliche Methode für die Datenbank ist die Verwaltung von Referenzzählern, die Aufschluss darüber geben, wie oft ein Objekt von anderen Objekten referenziert wird. Wenn der Referenzzähler für ein Objekt auf 0 abfällt, verweisen keine anderen Objekte mehr auf das Objekt, woraufhin das Objekt gelöscht werden kann. Es kann in Ordnung sein, Objekte mit einem Referenzzähler von null zu löschen, da ein Objekt, selbst wenn es nicht mehr referenziert wird, trotzdem abgefragt werden kann. Es muss eine datenbankweit gültige Richtlinie definiert werden, die festlegt, wann das Löschen von Objekten zulässig ist.

Abfrage

Die persistente Speicherung von Objekten ist nur wenig hilfreich, wenn kein Mechanismus für das Suchen und Abrufen spezieller Objekte vorhanden ist. Mit Abfragefunktionen können Anwendungen auf der Basis verschiedener Kriterien Objekte abfragen und abrufen. Die vom objektrelationalen Zuordnungs-Framework bereitgestellten Basisabfrageoperationen sind find und find unique. Die Operation find unique ruft ein bestimmtes Objekt ab, und find gibt eine Sammlung von Objekten basierend auf Abfragekriterien zurück.

Abfragefunktionen für Datenspeicher variieren erheblich. Einfache dateibasierte Datenspeicher können strenge, hausgemachte Abfrageoperationen implementieren, während relationale Systeme eine flexible Datenbearbeitungssprache unterstützten. Objektrelationale Zuordnungs-Frameworks erweitern das relationale Abfragemodell, um es von der Datenorientierung in Richtung Objektorientierung zu führen. Außerdem sind Pass-Through-Mechanismen implementiert, um die Flexibilität relationaler Abfragen und anbieterspezifische Erweiterungen (z. B. gespeicherte Prozeduren) nutzen zu können.

Manchmal treten Konflikte zwischen datenbankbasierten Abfragemechanismen und dem Objektkonzept auf. Die Abfragemechanismen der Datenbank werden über Werte von Attributen (Spalten) in einer Tabelle gesteuert. In den entsprechenden Objekten verhindert das Prinzip der Kapselung jedoch, dass die Werte der Attribute sichtbar sind. Die Werte werden von den Operationen der Klasse gekapselt. Die Kapselung bringt den Vorteil, dass sich Anwendungen einfacher ändern lassen. Die interne Struktur einer Klasse kann geändert werden, ohne sich Gedanken über die abhängigen Klassen zu machen, solange die öffentlich sichtbaren Operationen der Klassen nicht geändert werden. Ein Abfragemechanismus, der auf der Datenbank basiert, ist von der internen Darstellung einer Klasse abhängig und steht damit im Gegensatz zum Prinzip der Kapselung. Das Framework hat deshalb die herausfordernde Aufgabe zu verhindern, dass Abfragen die Anwendungen für Änderungen anfällig machen.

Transaktionen

Transaktionsunterstützung ermöglicht dem Anwendungsentwickler, eine atomare Arbeitseinheit zu definieren. In der Datenbankterminologie bedeutet dies, dass das System in der Lage sein muss, eine Reihe von Änderungen auf die Datenbank anzuwenden, oder sicherstellen muss, dass keine der Änderungen angewendet wird. Die Operationen in einer Transaktion müssen alle erfolgreich ausgeführt werden können, oder die Transaktion insgesamt scheitert. Objektrelationale Frameworks müssen mindestens eine der relationalen Datenbank ähnliche Funktion für das Festschreiben und Rückgängigmachen (COMMIT/ROLLBACK) von Transaktionen bereitstellen. Das Design objektrelationaler Frameworks in Mehrbenutzerumgebungen kann viele Herausforderungen mit sich bringen und muss deshalb sorgfältig überdacht werden.

Zusätzlich zu den vom Framework für die persistente Datenspeicherung bereitgestellten Funktionen muss die Anwendung wissen, wie Fehler behandelt werden. Wenn eine Transaktion scheitert oder abgebrochen wird, muss das System in der Lage sein, die Transaktion in einem stabilen Zustand wiederherzustellen. Hierfür werden in der Regel die vorherigen Zustandsinformationen aus der Datenbank gelesen. Deshalb besteht eine enge Interaktion zwischen dem Framework für persistente Datenspeicherung und dem Framework für die Fehlerbehandlung.

Parallelität

Objektorientierte Mehrbenutzersysteme müssen den gleichzeitigen Zugriff auf Objekte (Parallelität) steuern. Wenn mehrere Benutzer gleichzeitig auf ein Objekt zugreifen, muss das System einen Mechanismus bereitstellen, der sicherstellt, dass Änderungen am Objekt im persistenten Speicher in einer vorhersehbaren und kontrollierten Weise vorgenommen werden. Objektrelational Frameworks können pessimistische und/oder optimistische Steuerungselemente für den gemeinsamen Zugriff implementieren.

  • Die pessimistische Steuerung des gemeinsamen Zugriffs setzt voraus, dass der Anwendungsentwickler seine Absicht formuliert, wenn das Objekt aus dem Datenspeicher abgerufen wird (z. B. Lesezugriff, Schreibsperre usw.). Wenn Objekte gesperrt werden, können andere Benutzer blockiert werden, wenn sie auf das Objekt zugreifen, und dazu gezwungen werden, auf die Freigabe der Sperre zu warten. Eine pessimistische Steuerung des gemeinsamen Zugriffs sollte mit Sorgfalt verwendet und implementiert werden, da sie leicht zu Deadlock-Situationen führen kann.
  • Bei der optimistischen Steuerung des gemeinsamen Zugriffs wird angenommen, dass es unwahrscheinlich ist, dass mehrere Benutzer gleichzeitig auf dasselbe Objekt zugreifen. Konflikte beim gemeinsamen Zugriff werden festgestellt, wenn die Änderungen in der Datenbank gespeichert werden. Wenn das Objekt nach seinem Abruf von einem anderen Benutzer geändert wurde, wird ein Fehler an die Anwendung zurückgegeben, in dem das Scheitern der Änderungsoperation angezeigt wird. Die Anwendung ist dafür verantwortlich, den Fehler festzustellen und zu behandeln. Dies macht den Ruf nach einem Framework laut, das die parallelen Werte der Objekte speichert und sie mit der Datenbank vergleicht. Die optimistische Steuerung des gemeinsamen Zugriffs erzeugt weniger Kosten, wenn nur wenige Konflikte auftreten, ist aber teurer, wenn die Anzahl der Konflikte relativ hoch ist, weil in diesem Fall Arbeiten doppelt ausgeführt werden müssen.

Alle Anwendungen, die gemeinsame Daten verwenden, müssen dieselbe Strategie für die Steuerung des gemeinsamen Zugriffs verwenden. Wenn Sie für dieselben gemeinsamen Daten einmal eine optimistische und einmal eine pessimistische Steuerung des gemeinsamen Zugriffs verwenden, können die Daten beschädigt werden. Eine konsistente Strategie für die Steuerung des gemeinsamen Zugriffs wird am besten durch ein Framework für persistente Datenspeicherung gewährleistet.

Beziehungen

Objekte haben Beziehungen zu anderen Objekten. Ein Objekt Auftrag kann beispielsweise viele Objekte Position haben. Ein Objekt Buch kann viele Objekte Kapitel haben. Ein Objekt Mitarbeiter gehört zu genau einem Objekt Unternehmen. In relationalen Systemen werden Beziehungen zwischen Entitäten mit Fremdschlüssel/Primärschlüssel-Referenzen implementiert. In objektorientierten Systemen werden Relationen in der Regel explizit mit Attributen implementiert. Wenn ein Objekt Auftrag Positionen hat, enthält das Objekt Auftrag ein Attribut mit dem Namen Positionen. Das Attribut Positionen von Auftrag enthält viele Objekte Position.

Die Beziehungsaspekte eines objektrelationalen Framework sind von Persistenz-, Transaktions- und Abfrageservices unabhängig. Wenn ein Objekt gespeichert, abgerufen, bearbeitet oder abgefragt wird, müssen die zugehörigen Objekte berücksichtigt werden:

  • Müssen beim Abruf eines Objekts auch die zugeordneten Objekte abgerufen werden? Im Prinzip ja. Der Abruf der zugehörigen Objekte kann jedoch teuer werden, wenn diese Objekte nicht benötigt werden. Ein gutes Framework lässt eine Kombination von Strategien zu.
  • Müssen beim Speichern eines Objekts auch die zugeordneten Objekte gespeichert werden, wenn sie geändert wurden? Auch hier richtet sich die Antwort nach dem Kontext.

Obwohl es konzeptionell gesehen vorteilhaft ist, objektrelationale Services gesondert zu betrachten, sind die zugehörigen Implementierungen des objektrelationalen Framework jedoch von diesen Services abhängig. Die Services müssen nicht nur in einzelnen Organisationen konsistent implementiert werden, sondern in allen Anwendungen, die sich Daten teilen. Ein Framework ist die einzige ökonomische Lösung.