From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Wenn wir uns an die Tabelle dir
+aus Kapitel 42 erinnern, könnten
+wir auf die Idee kommen, dass diese auch durch eine Java Bean repräsentiert
+werden kann, deren Instanzen die Datensätze repräsentieren.
+Zur Erinnerung - und damit Sie nicht immer hin- und herblättern
+müssen - sei hier noch einmal die Tabellenstruktur angeführt:
+
+
+
+Tabelle 45.1: Die Struktur der dir-Tabelle
+Der Einfachheit halber wollen wir uns hier auf die Tabelle dir
+der Datenbank konzentrieren, obwohl die Java Bean für die Klasse
+file ganz analog wäre. Hierfür entwerfen wir zunächst
+eine einfache Javaklasse mit Variablen, die den Attributen der Datenbank-Tabelle
+entsprechen. Jede Instanz der Klasse kann damit eine Zeile bzw. einen
+Datensatz der Tabelle repräsentieren.
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 45 - Objektorientierte Persistenz
+
+
+
+
+
+45.2 Datenbank-Tabellen und Javaobjekte
+
+
+
+
+
+
+
+45.2.1 Eine einfache Javaklasse für Tabellen
+
+
+
+
+
+
+Name
+Typ
+Bedeutung
+
+did
+INT
+Primärschlüssel
+
+dname
+CHAR(100)
+Verzeichnisname
+
+fatherdid
+INT
+Schlüssel Vaterverzeichnis
+
+entries
+INT
+Anzahl der Verzeichniseinträge
+
+
+Listing 45.1: Eine Klasse für die dir-Tabelle
+
+
+
+
+
+001 /**
+002 * Diese Klasse repräsentiert die Tabelle 'dir' der 'DirDB'
+003 * Jede Instanz der Klasse repräsentiert wiederum einen
+004 * Datensatz
+005 */
+006 public class Directory {
+007
+008 // Variablen die den Attributen der Tabelle entsprechen
+009 private int did;
+010 private String dname;
+011 private int fatherid;
+012 private int entries;
+013
+014 /**
+015 * Ein einfacher Konstruktor ohne Initialisierung der
+016 * Objektvariablen
+017 */
+018 public Directory() {
+019 }
+020
+021 /**
+022 * Konstruktor zum Erzeugen von Instanzen der Klasse
+023 */
+024 public Directory(int did,
+025 String dname,
+026 int fatherid,
+027 int entries)
+028 {
+029 this.did = did;
+030 this.dname = dname;
+031 this.fatherid = fatherid;
+032 this.entries = entries;
+033 }
+034
+035 // Zugriffsmethoden, um die Daten
+036 // Lesen und Schreiben zu können
+037 public int getDid()
+038 {
+039 return did;
+040 }
+041
+042 public void setDid(int did)
+043 {
+044 this.did = did;
+045 }
+046
+047 public String getDname()
+048 {
+049 return dname;
+050 }
+051
+052 public void setDname(String dname)
+053 {
+054 this.dname = dname;
+055 }
+056
+057 public int getFatherid()
+058 {
+059 return fatherid;
+060 }
+061
+062 public void setFatherid(int fatherid)
+063 {
+064 this.fatherid = fatherid;
+065 }
+066
+067 public int getEntries()
+068 {
+069 return entries;
+070 }
+071
+072 public void setEntries(int entries)
+073 {
+074 this.entries = entries;
+075 }
+076
+077 public String toString()
+078 {
+079 return "Directory[id:"+ did + ", name:" + dname + "]";
+080 }
+081 }
+
+
+Wie wir sehen enthält die Klasse Directory +für jedes Datenbank-Attribut eine äquivalente Variable, +die über Getter-Methoden ausgelesen und über Setter-Methoden +verändert werden kann. Derartige Javaobjekte werden auch als +Java Beans bezeichnet, die wir in Abschnitt 44.1 +kennen gelernt haben. + + + + +
+Die soeben erstellte Javaklasse ist sehr einfach und entspricht auf +triviale Weise der Datenbank-Tabelle, jedoch müssen wir diese +Verknüpfung Java auch direkt und unmissverständlich anzeigen. +Hierzu bedienen wir uns zusätzlicher Metainformationen in Form +so genannter Annotationen, die in Abschnitt 43.6 +beschrieben wurden. + +
+Diese Metainformationen beeinflussen die Klasse oder den Programmablauf +in keiner Weise, können jedoch zur Laufzeit - zum Beispiel über +die Reflection API - ausgelesen werden. Die in den Annotationen hinterlegten +Informationen teilen der Persistenzschicht dabei mit, welche Tabelle +der Datenbank und welche Spalten auf die jeweiligen Attribute abgebildet +werden. Das folgende Listing zeigt die hierfür notwendigen Erweiterungen: + + +
+
+
+
+001 import javax.persistence.*;
+002
+003 /**
+004 * Diese Klasse repräsentiert die Tabelle 'dir' der 'DirDB'
+005 * Jede Instanz der Klasse repräsentiert wiederum einen
+006 * Datensatz
+007 */
+008 @Entity
+009 @Table( name = "dir" )
+010 public class Directory {
+011
+012 // Variablen die den Attributen der Tabelle entsprechen
+013 private int did;
+014 private String dname;
+015 private int fatherid;
+016 private int entries;
+017
+018 /**
+019 * Ein einfacher Konstruktor ohne Initialisierung der
+020 * Objektvariablen
+021 */
+022 public Directory() {
+023 }
+024
+025 /**
+026 * Konstruktor mit Initialisierung der Variablen
+027 */
+028 public Directory(int did,
+029 String dname,
+030 int fatherid,
+031 int entries)
+032 {
+033 this.did = did;
+034 this.dname = dname;
+035 this.fatherid = fatherid;
+036 this.entries = entries;
+037 }
+038
+039 // Zugriffsmethoden, um die Daten der Klasse
+040 // Auslesen und Schreiben zu können
+041 @Id
+042 @Column( name = "id" )
+043 public int getDid()
+044 {
+045 return did;
+046 }
+047
+048 public void setDid(int did)
+049 {
+050 this.did = did;
+051 }
+052
+053 @Column( name = "dname", nullable = false )
+054 public String getDname()
+055 {
+056 return dname;
+057 }
+058
+059 public void setDname(String dname)
+060 {
+061 this.dname = dname;
+062 }
+063
+064 @Column ( name = "fatherid" )
+065 public int getFatherid()
+066 {
+067 return fatherid;
+068 }
+069
+070 public void setFatherid(int fatherid)
+071 {
+072 this.fatherid = fatherid;
+073 }
+074
+075 @Column ( name = "entries" )
+076 public int getEntries()
+077 {
+078 return entries;
+079 }
+080
+081 public void setEntries(int entries)
+082 {
+083 this.entries = entries;
+084 }
+085
+086 public String toString()
+087 {
+088 return "Directory[id:"+ did + ", name:" + dname + "]";
+089 }
+090 }
+
+ |
++Directory.java | +
+Wenn wir dieses Listing mit dem vorangegangenen vergleichen, sehen +wir, dass lediglich einige Annotationen hinzugekommen sind. Sie enthalten +Informationen, die Java benötigt, um die Instanzen der Klasse +mit der Tabelle in der Datenbank zu verknüpfen. Die Annotationen +für das Java Persistenz API können entweder über den +Variablen der Klasse selbst oder über die damit verknüpften +Getter-Methoden stehen. Die Reihenfolge der Methoden spielt keine +Rolle. + +
+Die Annotationen haben folgende Bedeutung: + +
+
| Annotation | +Beschreibung |
| @Entity + | +Markiert die Klasse als persistierbares, +dass heißt mit einer Datenbank verknüpftes Objekt |
| @Table + | +Bezeichnet die verknüpfte Datenbanktabelle |
| @Id + | +Markiert das Attribut als Primärschlüssel +der Datenbank. Das ist z.B. für Suchoperationen wichtig |
| @Column + | +Verknüpft das Attribut mit einer Datenbankspalte |
+Tabelle 45.2: Die Struktur der dir-Tabelle
+ ++Die Annotationen Table +und Column +besitzen jeweils das Attribut name, +das den Namen der verknüpften Tabelle bzw. Spalte enthält. +Ist dieser Name identisch mit dem Namen des Javaattributes kann die +Angabe auch weggelassen werden. Allerdings empfehlen wir Ihnen - schon +allein um die Dokumentation zu erhöhen - diese Angabe mit aufzunehmen. +Zeile 053 zeigt zudem, dass +die Annotationen weitere Attribute aufnehmen können, mit denen +die Struktur und Beschränkungen der Datenbank granular konfiguriert +werden können. + +
+Die Annotation @Column unterstützt +folgende Attribute + +
+
| Attribut | +Typ | +Beschreibung | +Standardwert |
| name + | +String + | +Name der Tabellenspalte | +Name des Java Bean Attributs |
| length + | +int + | +Maximale Länge des Eintrags | +255 |
| table + | +String + | +Name einer Tabelle | +Namen der Tabelle dieser Java Bean |
| nullable + | +boolean + | +Sind null-Werte +erlaubt? | +true |
| insertable + | +boolean + | +Darf dieser Wert mit INSERT Statements verändert +werden? | +true |
| updateable + | +boolean + | +Darf dieser Wert mit UPDATE Statements geändert +werden? | +true |
+Tabelle 45.3: Attribute der Annotation @Column
++
![]() |
+![]() |
+
+
+ +Egal welche Konstruktoren wir für die mit der Datenbank verknüpfte +Java Bean vorsehen, das Persistenz Framework benötigt zusätzlich +einen »leeren« Standardkonstruktor. Bei Bedarf können +Sie dessen Sichtbarkeit auch auf protected +setzen und damit für andere Klassen weitestgehend einschränken. +Er muss jedoch vorhanden sein, da das Framework sonst nicht mit der +Java Bean arbeiten kann! |
+
+
|
+![]() |
+
+Jetzt haben wir eine Java Bean erstellt, die in der Lage, ist einen +Datensatz der Tabelle dir aufzunehmen +und diese zudem mit Zusatzinformationen ausgestattet, um die Verknüpfung +zwischen Datenbank auf Javaklasse beschreiben. Was noch fehlt sind +Informationen darüber, in welcher Datenbank sich die entsprechenden +Tabellen befinden. + +
+Natürlich könnten diese Informationen theoretisch ebenfalls +in der Javaklasse abgelegt werden, dies würde jedoch zu unflexiblem +Code führen, der nicht mit verschiedenen Datenbanken zusammenarbeiten +könnte. Um die tatsächliche Datenbank auch im Nachhinein +flexibel austauschen und beispielsweise statt der Hypersonic DB eine +Access Datenbank verwenden zu können, werden diese Konfigurationsdaten +in einer separaten Datei gepflegt. Diese wird auch als Persistence +Descriptor bezeichnet und könnte +beispielsweise folgende Form haben: + + +
+
+
++001 <?xml version="1.0" encoding="ISO-8859-1"?> +002 +003 <!-- Persistenz Descriptor zur Konfiguration --> +004 <persistence> +005 +006 <!-- Hinterlegen eines symbolischen Namens --> +007 <persistence-unit name="persistenceExample" +008 transaction-type="RESOURCE_LOCAL"> +009 +010 <!-- Zu verwendende Implementierung --> +011 <provider>org.hibernate.ejb.HibernatePersistence</provider> +012 +013 <!-- Persistierbare Klassen --> +014 <class>Directory</class> +015 +016 <!-- Konfiguration der Hibernate Implementierung --> +017 <properties> +018 <!-- Name des intern verwendeten JDBC-Treibers --> +019 <property name="hibernate.connection.driver_class" +020 value="org.hsqldb.jdbcDriver"/> +021 +022 <!-- URL der zu verwendenden Datenbank --> +023 <property name="hibernate.connection.url" +024 value="jdbc:hsqldb:hsqldbtest"/> +025 +026 <!-- SQL-Dialect, den Hibernate verwenden soll --> +027 <property name="hibernate.dialect" +028 value="org.hibernate.dialect.HSQLDialect"/> +029 +030 <!-- Benutzername und Passwort; Standardwerte der HSQLDB --> +031 <property name="hibernate.connection.username" value="SA"/> +032 <property name="hibernate.connection.password" value=""/> +033 +034 <!-- Flag, ob Tabellen automatisch erzeugt werden sollen --> +035 <property name="hibernate.hbm2ddl.auto" value="create"/> +036 +037 <!-- Flag, ob SQL-Statements ausgegeben werden sollen --> +038 <property name="hibernate.show_sql" value="true"/> +039 </properties> +040 </persistence-unit> +041 </persistence>+ + |
++persistence.xml | +
+Diese Datei muss unter dem Namen persistence.xml +im Classpath abgelegt werden, und schon kann das Persistenz API die +Klasse Directory mit der Tabelle +dir in der HSQLDB verknüpfen. +Am einfachsten ist dies zu bewerkstelligen, indem die Datei persistence.xml +gemeinsam mit der kompilierten Class-Datei Directory.class +gespeichert wird. + + + + +
+Die Konfigurationsdatei ist in einzelne Seqmente aufgeteilt, die verschiedene +Aufgaben besitzen. Listing 45.3 +ist so vorkonfiguriert, dass es mit der HSQLDB aus Kapitel Kapitel 42 +verwenden werden kann. Um auf die Tabellen einer anderen Datenbank +zuzugreifen müssen der Datenbanktreiber, die URL und die Zugangsdaten +angepasst werden. Wenn wir dieses Listing mit Listing 42.3 +vergleichen, sollten uns viele Optionen vertraut vorkommen. Diese +sind nun nicht mehr fest in die Javaklasse einkompiliert, sondern +können in einer separaten Datei gewartet werden. + +
+
| Zeile | +Beschreibung der Konfigurationseinstellung |
| Zeile 007 + | +Ein symbolischer Name für die Konfiguration, +den wir später für den Zugriff verwenden werden |
| Zeile 014 + | +Liste der Klassen, die mit der Datenbank +verknüpft werden sollen |
| Zeile 020 + | +Name des passenden JDBC-Treibers |
| Zeile 024 + | +Name der Datenbank |
| Zeile 031 + | +Benutzername für den Zugriff auf die +Datenbank |
| Zeile 032 + | +Passwort für den Zugriff auf die Datenbank |
| Zeile 035 + | +Gibt an, ob die Tabellen bei Bedarf dynamisch +erstellt werden sollen |
| Zeile 038 + | +Gibt an, ob die intern verwendeten SQL-Statements +auf der Kommandozeile ausgegeben werden sollen |
+Tabelle 45.4: Anpassen der Konfigurationsdatei
+ ++Nachdem wir die Datei persistence.xml +zusammen mit der Directory-Class +abgelegt haben können wir nun mit dem Java Persistenz API arbeiten +
+
![]() |
+
+
+ +Die vorangegangenen Schritte erscheinen Ihnen vielleicht aufwändiger +als die vermeintlichen Pendants im Kapitel über JDBC. Der Vorteil +des Java Persistenz API liegt jedoch vor allem in der wesentlich einfacheren +Anwendung, mit der wir uns im folgenden Abschnitt beschäftigen +werden. + + +Die gute Nachricht ist: Nachdem wir die Verknüpfung zwischen +Javaklasse und Datenbank nun konfiguriert haben, können wir nachfolgend +einfach mit der Directory-Klasse +arbeiten, ohne uns weiter um SQL oder Datenbank-Aspekte kümmern +zu müssen. |
+
+
|
+![]() |
+
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |