Daniel Röder JPA mit Hibernate...Inhaltsverzeichnis JPA mit Hibernate 9 7.3 Native SQL 169 7.4...

27

Transcript of Daniel Röder JPA mit Hibernate...Inhaltsverzeichnis JPA mit Hibernate 9 7.3 Native SQL 169 7.4...

Daniel Röder

JPA mit Hibernate

Daniel Röder

JPA mit HibernateJava Persistence API in der Praxis

Daniel Röder: JPA mit HibernateJava Persistence API in der PraxisISBN: 978-3-86802-240-7

© 2010 entwickler.pressEin Imprint der Software & Support Verlag GmbH

Bibliografische Information der Deutschen Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.

Ihr Kontakt zum Verlag und Lektorat:Software & Support Verlag GmbHentwickler.pressGeleitsstraße 1460599 Frankfurt am MainTel: +49(0) 69 63 00 89 - 0Fax: +49(0) 69 63 00 89 - [email protected]://www.entwickler-press.de

Lektorat: Sebastian BurkartKorrektorat: Frauke PeschLayout: SatzWERK, Siegen (www.satz-werk.com)Umschlaggestaltung: Maria RudiBelichtung, Druck & Bindung: M.P. Media-Print Informationstechnologie GmbH, Paderborn

Alle Rechte, auch für Übersetzungen, sind vorbehalten. Reproduktion jeglicher Art (Fotokopie, Nachdruck, Mikrofilm, Erfassung auf elektronischen Datenträgern oder andere Verfahren) nur mit schriftlicher Genehmigung des Verlags. Jegliche Haftung für die Richtigkeit des gesamten Werks kann, trotz sorgfältiger Prüfung durch Autor und Verlag, nicht übernommen werden. Die im Buch genannten Produkte, Warenzeichen und Firmennamen sind in der Regel durch deren Inhaber geschützt.

JPA mit Hibernate 5

Inhaltsverzeichnis

V Vorwort 15

V.1 Aufbau des Buches 15

V.2 Webseite zum Buch 16

V.3 Danksagung 16

1 Einleitung 17

1.1 Impedance Mismatch 171.1.1 Granularität 171.1.2 Vererbung 181.1.3 Objektidentität 181.1.4 Beziehungen 181.1.5 Graphennavigation 19

1.2 Hibernate 19

1.3 Java Persistence API 20

2 Hibernate, Java und das Java Persistence API – Ein Überblick 21

2.1 Java 5 und höher 212.1.1 Annotations 212.1.2 Generics 23

2.2 Das Java Persistence API 272.2.1 Entities 272.2.2 Entity Manager und Persistenzkontext 282.2.3 Java Persistence QL und die EJB QL 29

2.3 Hibernate 302.3.1 Architektur im Überblick 302.3.2 Schnittstellen 322.3.3 Module 33

2.4 Zusammenfassung 38

Inhaltsverzeichnis

6

3 Einführung in Hibernate und JPA 39

3.1 Beispielprojekt 393.1.1 Die Anwendungsfälle 393.1.2 Das Klassendiagramm 403.1.3 Projekt einrichten 413.1.4 Testen 44

3.2 Klassisches Hibernate 443.2.1 Hibernate-Konfiguration 453.2.2 Entity „User“ 463.2.3 HibernateUtil 483.2.4 Data Access Object 493.2.5 Testen des DAOs 53

3.3 Hibernate mit Annotations 543.3.1 Hibernate-Konfiguration 543.3.2 Entity „User“ 543.3.3 HibernateUtil 553.3.4 Data Access Object 553.3.5 Testen des DAOs 55

3.4 Hibernate als JPA Persistence Provider 563.4.1 Konfiguration des Persistence Providers 563.4.2 Die Entity „User“ 573.4.3 HibernateUtil 573.4.4 Data Access Object 583.4.5 Testen des DAOs 60

3.5 Hibernate als Persistenzschicht im Application Server 603.5.1 Konfiguration des Persistence Providers 603.5.2 Die Entity „User“ 613.5.3 HibernateUtil 613.5.4 SessionBean als Data Access Object 613.5.5 Testen der SessionBean mit Web-Service-Schnittstelle 63

3.6 Zusammenfassung 63

4 Der Aufbau und das Mapping von Entities 65

4.1 Anforderungen an eine Entity 654.1.1 Definition der Tabellen- und Spaltennamen 674.1.2 Erweiterungen der Entity mit Hibernate 68

Inhaltsverzeichnis

JPA mit Hibernate 7

4.2 Primärschlüssel 704.2.1 Anforderungen an den Primärschlüssel 704.2.2 Datenbankidentität, Objektidentität und -gleichheit 714.2.3 Generatoren für den Primärschlüssel 72

4.3 Komponenten 74

4.4 Assoziationen 784.4.1 1-zu-1-Beziehungen 784.4.2 1-zu-n- und n-zu-1-Beziehungen 834.4.3 N-zu-m-Beziehungen 874.4.4 Transitive Persistenz 88

4.5 Vererbung 924.5.1 SINGLE_TABLE 934.5.2 TABLE_PER_CLASS 944.5.3 JOINED 96

4.6 Collections 974.6.1 Persistente Collections 974.6.2 Collections mit Index oder Schlüssel 1004.6.3 Sortierte Collections 104

4.7 Enumerations 106

4.8 Zusammenfassung 107

5 Lebenszyklus einer Entity 109

5.1 Die Zustände einer Entity 1095.1.1 Transient 1095.1.2 Persistent 1105.1.3 Detached 110

5.2 Zustandsänderungen einer Entity 1115.2.1 Allgemeines zum Synchronisieren von Entities 1115.2.2 Methoden des EntityManagers 1115.2.3 Besonderheiten der Hibernate Session 114

5.3 Verwendung von Detached Entities 115

5.4 Callback-Methoden und Entity Listener 1185.4.1 Beschreibung der Callback-Methoden 1185.4.2 Verwendung von Entity-Listener-Klassen 1225.4.3 Default Entity Listener 1235.4.4 Ausführungsreihenfolge gleicher Callback-Methoden 124

5.5 Zusammenfassung 125

Inhaltsverzeichnis

8

6 Transaktionen, EntityManager und Persistenzkontext 127

6.1 Transaktionen 1276.1.1 Was ist eine Transaktion? 1276.1.2 Isolationsebenen 1286.1.3 Transaktionssteuerung in JPA 129

6.2 Locking 1306.2.1 Optimistisches Locking 1336.2.2 Lock-Modi von JPA und Hibernate 1366.2.3 Erweiterte Einstellungen für das Locking in Hibernate 138

6.3 Entity Manager und Persistenzkontext 1396.3.1 Arten und Lebenszyklus des Persistenzkontexts 1396.3.2 Erzeugen eines EntityManagers 140

6.4 Patterns für EntityManager und Hibernate Session 1436.4.1 „EntityManger/Session per Request“-Pattern 1436.4.2 „EntityManager/Session per Conversation“-Pattern 1456.4.3 „EntityManager/Session per Operation“- und

„EntityManager/Session per Application“-Antipattern 147

6.5 Zusammenfassung 148

7 Datenbankabfragen mit JPA und Hibernate 149

7.1 Das Query Interface 1497.1.1 Ausführung der Abfragen 1497.1.2 Parameter Binding 1527.1.3 Definition von benannten Abfragen in den Metadaten 153

7.2 Die Java Persistence Query Language 1547.2.1 Allgemeines 1547.2.2 Übersicht der Beispieldaten 1547.2.3 Grundaufbau der Abfragen 1557.2.4 Einschränkung der Ergebnismenge mit „where“ 1567.2.5 Sortierung mit „order by“ 1627.2.6 Joins 1637.2.7 Die „select“-Anweisung im Detail 1657.2.8 Aggregatfunktionen 1667.2.9 Die „group by“-Anweisung 1677.2.10 Polymorphe Abfragen 1687.2.11 Subqueries 1697.2.12 Massen-Update und -Delete 169

Inhaltsverzeichnis

JPA mit Hibernate 9

7.3 Native SQL 169

7.4 Criteria API in Hibernate 1727.4.1 Ausführung der Abfragen 1727.4.2 Einschränkung der Ergebnismenge mit Restrictions 1737.4.3 Sortierung mit org.hibernate.criterion.Order 1767.4.4 Assoziationen 1777.4.5 Abfragen mit org.hibernate.criterion.Example 1787.4.6 Die Klasse org.hibernate.criterion.DetachedCriteria 178

7.5 Hibernate-Filter 179

7.6 Criteria API und Metamodell in JPA 2.0 1807.6.1 Das statische Metamodell 1807.6.2 Das dynamische Metamodell 1827.6.3 Das Criteria API 183

7.7 Zusammenfassung 185

8 Fetching-Strategien und Caches 187

8.1 Fetching-Strategien 1878.1.1 Fetch Joins 1908.1.2 Batch Fetching mit Hibernate 1928.1.3 Subselect-Fetching mit Hibernate 194

8.2 Hibernate Query und Second Level Cache 1958.2.1 Strategien und Konfiguration 1978.2.2 Second Level Cache Provider 198

8.3 Zusammenfassung 198

9 Hibernate Types 199

9.1 Hibernate Mapping Types 199

9.2 Benutzerdefinierte Mapping Types 201

9.3 Zusammenfassung 208

A Referenz der Annotationen 209

A.1 Metadata-Annotationen 209A.1.1 Entity 209

Inhaltsverzeichnis

10

A.2 Callback-Annotationen 210A.2.1 EntityListeners 210A.2.2 ExcludeSuperclassListeners 210A.2.3 ExcludeDefaultListeners 210A.2.4 PrePersist 211A.2.5 PostPersist 211A.2.6 PreRemove 211A.2.7 PostRemove 212A.2.8 PreUpdate 212A.2.9 PostUpdate 212A.2.10 PostLoad 212

A.3 Annotationen für Datenbankabfragen 213A.3.1 NamedQuery 213A.3.2 QueryHint 213A.3.3 NamedQueries 213A.3.4 NamedNativeQuery 214A.3.5 NamedNativeQueries 214

A.4 Abbilden der SQL-Abfrageergebnisse 215A.4.1 SQLResultSetMapping 215A.4.2 SQLResultSetMappings 215A.4.3 EntityResult 216A.4.4 FieldResult 216A.4.5 ColumnResult 216

A.5 Referenzen auf den EntityManager und die EntityManagerFactory 217A.5.1 PersistenceContext 217A.5.2 PersistenceProperty 217A.5.3 PersistenceContexts 218A.5.4 PersistenceUnit 218A.5.5 PersistenceUnits 218

A.6 Annotationen für die Definition der Abbildungen der Entitäten 219A.6.1 Table 219A.6.2 UniqueConstraint 219A.6.3 SecondaryTable 220A.6.4 SecondaryTables 220A.6.5 CollectionTable 221

Inhaltsverzeichnis

JPA mit Hibernate 11

A.7 Definieren von Primärschlüsseln 222A.7.1 Id 222A.7.2 GeneratedValue 222A.7.3 EmbeddedId 222A.7.4 IdClass 223A.7.5 SequenceGenerator 223A.7.6 TableGenerator 224A.7.7 MapsId 224

A.8 Annotationen zum Überschreiben bestehender Abbildungen 225A.8.1 AttributeOverride 225A.8.2 AttributeOverrides 225A.8.3 AssociationOverride 226A.8.4 AssociationOverrides 226

A.9 Annotationen für Entitätseigenschaften 227A.9.1 Transient 227A.9.2 Column 227A.9.3 Basic 228A.9.4 Lob 228A.9.5 Temporal 229A.9.6 Enumerated 229A.9.7 Version 229A.9.8 Access 230A.9.9 Cacheable 230

A.10 Annotationen für Assoziationen 231A.10.1 JoinColumn 231A.10.2 JoinColumns 231A.10.3 ManyToOne 232A.10.4 OneToOne 232A.10.5 OneToMany 233A.10.6 ManyToMany 233A.10.7 JoinTable 234A.10.8 MapKey 234A.10.9 MapKeyClass 235A.10.10 MapKeyColumn 235A.10.11 MapKeyEnumerated 236A.10.12 MapKeyJoinColumn 236A.10.13 MapKeyJoinColumns 237A.10.14 MapKeyTemporal 237A.10.15 OrderBy 237

Inhaltsverzeichnis

12

A.10.16 OrderColumn 238A.10.17 PrimaryKeyJoinColumn 238A.10.18 PrimaryKeyJoinColumns 239A.10.19 ElementCollection 239

A.11 Annotationen für Vererbung 240A.11.1 Inheritance 240A.11.2 DiscriminatorColumn 240A.11.3 DiscriminatorValue 241A.11.4 MappedSuperclass 241

A.12 Annotationen für eingebettete Komponenten 242A.12.1 Embeddable 242A.12.2 Embedded 242

A.13 Hibernate-spezifische Annotationen 243A.13.1 Entity 243A.13.2 Table 244A.13.3 Index 244A.13.4 Tables 244A.13.5 Proxy 245A.13.6 AccessType 245A.13.7 BatchSize 245A.13.8 Cache 246A.13.9 Cascade 246A.13.10 Check 247A.13.11 CollectionOfElements 247A.13.12 Columns 247A.13.13 DiscriminatorFormula 248A.13.14 Fetch 248A.13.15 Filter 248A.13.16 Filters 249A.13.17 FilterDef 249A.13.18 ParamDef 249A.13.19 FilterDefs 250A.13.20 Formula 250A.13.21 Generated 250A.13.22 GenericGenerator 251A.13.23 Parameter 251A.13.24 IndexColumn 251A.13.25 LazyCollection 252A.13.26 LazyToOne 252

Inhaltsverzeichnis

JPA mit Hibernate 13

A.13.27 MapKey 252A.13.28 MapKeyManyToMany 253A.13.29 NamedNativeQuery 253A.13.30 NamedNativeQueries 254A.13.31 NamedQuery 254A.13.32 NamedQueries 255A.13.33 NotFound 255A.13.34 OnDelete 255A.13.35 OrderBy 256A.13.36 Parent 256A.13.37 Sort 256A.13.38 Type 257A.13.39 TypeDef 257A.13.40 TypeDefs 257A.13.41 Where 258

B Literaturverzeichnis 259

Stichwortverzeichnis 261

JPA mit Hibernate 15

VVorwort

In jedem Softwareprojekt muss man sich über die Speicherung der Daten Gedanken machen. Für Konfigurationen und wenige Daten reicht es meistens aus, diese in einfa-chen Property oder XML-Dateien abzulegen. Jedoch kommt man bei größeren Daten-mengen meistens nicht an der Verwendung einer Datenbank vorbei. Mit Java gibt es ver-schiedene Ansätze Daten in einer Datenbank abzulegen. Dabei ist die Verwendung von JDBC1 die Basis von vielen Möglicheiten, da damit SQL Statements direkt an die Daten-bank geschickt werden können. Um aber nicht in jedem Projekt das Rad bzw. die Persis-tenz der Daten neu erfinden zu müssen, gibt es zahlreiche Frameworks, wie bspw. Hiber-nate, die die typischen Funktionen in der Verwendung von JDBC kapseln. Da aber jedes Framework verschieden ist, wurde mit der Java Persistence API (JPA) eine einheitliche Schnittstelle (API) für die Persistenz in Java spezifiziert, die mittlerweile von zahlreichen Frameworks unterstützt wird. Das Buch zeigt anhand von vielen Beispielen die Möglich-keiten und die Verwendung der Java Persistence API. Dabei wird mit Hibernate auf eine solide Implementierung der JPA gesetzt.

V.1 Aufbau des BuchesIn Kapitel 1 werden zunächst die Schwierigkeiten beim Speichern von Objekten in rela-tionalen Datenbanken beleuchtet und erklärt, welche Herausforderungen sich dadurch ergeben. Des weiteren werden die „Protagonisten“ des Buches, JPA und Hibernate, vor-gestellt.

Kapitel 2 gibt einen tieferen Überblick über die Java Persistence API und deren Begriff-lichkeiten sowie die Hibernate Projekte. Außerdem werden Annotations und Generics vorgestellt, deren Kenntnis für die Verwendung der JPA unerlässlich ist. In Kapitel 3 wird das im Buch durchgängig verwendete Beispiel vorgestellt. Dabei wird besonders auf die möglichen Anwendungsszenarien von Hibernate eingegangen.

Kapitel 4 befasst sich mit dem grundlegenden Aufbau von Entites. Dabei wird auch die Verwendung von Komponenten, Assoziationen, Collections und Vererbung diskutiert. Der Lebenszyklus der Entities findet in Kapitel 5 Beachtung. Der EntityManager und die Möglichkeiten zur Transaktionssteuerung und für das Locking werden in Kapitel 6beleuchtet.

In Kapitel 7 wird der Frage nachgegangen wie gespeicherte Entites in der Datenbank gesucht und gefunden werden können. Zu diesem Zweck werden die Java Persistence Query Language (JPQL) und die Criteria APIs von JPA und Hibernate vorgestellt.

1. JDBC Überblick, http://java.sun.com/products/jdbc/overview.html

V – Vorwort

16

Die Strategien für das Fetching und Caching von Entites werden in Kapitel 8 erläutert. In Kapitel 9 kommen zum Schluss die Hibernate Custom Types zum Zug.

Im Anhang befindet sich eine Auflistung der Annotationen zur Angabe der Metadaten in JPA und Hibernate.

V.2 Webseite zum BuchAuf der Webseite http://www.entwickler-press.de/jpa befindet sich der gesamte Quellcode, der in den einzelnen Kapiteln verwendet wurde.

V.3 DanksagungIch bedanke mich bei Markus Kehle und Robert Hien, die mit dem Buch „Hibernate und die Java Persistence API“ die Grundlage für mein Buch lieferten. Sie gaben mir die Chance aus dem Ihren das Meinige zu machen. Weiterhin möchte ich mich bei Erik Bens bedanken, der mir durch sein Review wertvolle und hilfreiche Tipps gegeben hat. Mein Dank gilt auch meinem Arbeitgeber der Saxonia Systems AG, der mir den Rahmen für die Arbeit an dem Buch zur Verfügung stellte. Vielen Dank auch an die Lektoren Christi-ane Auf, Sandra Michel, Maike Möws und Sebastian Burkart, die mir während der lan-gen Arbeitsphase mit viel Geduld sowie Rat und Tat zur Seite standen. Schließlich möchte ich mich noch bei meiner Frau Nadine für ihre Rücksicht und Unterstützung während der langen Entstehungszeit des Buches bedanken.

JPA mit Hibernate 17

1 Einleitung

In diesem einleitenden Kapitel soll auf die Herausforderungen eingegangen werden, die bei der Speicherung von Objekten in relationalen Datenbanken entstehen können. Außerdem wird die Java Persistence API und Hibernate kurz vorgestellt.

1.1 Impedance MismatchIn der Softwareentwicklung ist mit Impedance Mismatch der Unterschied in der Struktur zwischen normalisierten relationalen Datenbanken und objektorientierten Klassenhie-rarchien gemeint. Die Unterschiede liegen in der Granularität, in der Vererbung, bei der Objektidentität, in den Beziehungen und in der Graphennavigation. Diese Unterschiede werden in den nächsten Abschnitten erläutert.

Relationale Datenbanken repräsentieren Daten in zweidimensionalen Tabellen. Ein Ein-trag in einer Tabelle hat einen Primärschlüssel, mit dem der Eintrag eindeutig identifi-ziert werden kann. Weiterhin gibt es Fremdschlüssel, die Tabellen miteinander in Bezie-hung bringen, indem sie auf Primärschlüssel einer anderen Tabelle zeigen.

1.1.1 Granularität

Ein objektorientiertes Modell ist typischerweise sehr feingranular, so kann es beispiels-weise eine Entity Person geben, die eine Entity Adresse als Attribut hat (siehe Abbildung 1.1).

Abbildung 1.1: Klasse Person hat eine Adresse

Objekte können jegliche Granularität haben, Tabellen hingegen sind bezüglich der Granularität beschränkt. In einer relationalen Datenbank sind die Daten der Person inklusive den Adressdaten normalerweise in einer Tabelle abgelegt (siehe Tabelle 1.1).

ID Vorname Nachname ... Adresse_PLZ Adresse_Stadt ...

1 Max Mustermann ... 01234 Musterstadt ...

2 ... ... ... ... ... ...

Tabelle 1.1: Rationale Datenbanktabellen mit Person- und Adressdaten

Person

Adresse

1 – Einleitung

18

Mit welchen Mitteln man ein feingranulares Objektmodell in zweidimensionalen Tabel-len abbilden kann, wird in Kapitel 4.3 gezeigt.

1.1.2 Vererbung

Vererbung ist in Programmiersprachen wie Java selbstverständlich. Relationale Daten-banken kennen aber keine Vererbung. In Kapitel 4.5 wird gezeigt, welche Strategien es zur Abbildung von Vererbungshierarchien gibt und welche Vor- und Nachteile die jeweilige mit sich bringt.

1.1.3 Objektidentität

In Java sind zwei Objekte identisch, wenn beide dasselbe Objekt sind. Wenn zwei Objekte identische Werte enthalten, dann sind die Objekte gleich, aber nicht unbedingt identisch. Objektidentität wird in Java mit dem == Operator überprüft, Objektgleichheit mit equals().

Objektidentität in Java:

Objektgleichheit in Java:

In relationalen Datenbanken wird ein Eintrag in einer Tabelle über die Daten, die er ent-hält, identifiziert; damit können gleiche Datensätze gefunden werden. Allerdings kann man nicht sicherstellen, dass diese identisch sind. Um nun für ein Objekt den entspre-chenden identischen Eintrag in der Datenbank zu finden, muss ein eindeutiger Primär-schlüssel eingeführt werden. In den Objekten wird dieser Primärschlüssel ebenso einge-fügt und somit kann über diesen die Identität zwischen Objekt und Eintrag in der Datenbank gewährleistet werden.

1.1.4 Beziehungen

Beziehungen gibt es auch in relationalen Datenbanken. Mit einem Fremdschlüssel in der einen Tabelle wird ein Primärschlüssel in einer anderen Tabelle referenziert und somit die Tabellen in Beziehung gebracht. In der objektorientierten Welt gibt es mehrere Arten von Beziehungen:

� 1-zu-1-,

� 1-zu-viele-,

� viele-zu-1- und

� viele-zu-viele-Beziehungen.

objektA == objektB;

objektA.equals(objektB);

Hibernate

JPA mit Hibernate 19

Diese können letztendlich alle mit Fremdschlüsseln abgebildet werden. Etwas kompli-zierter ist die 1-zu-viele-Beziehung, da dort ein Primärschlüssel einen Fremdschlüssel referenziert und bei der viele-zu-viele-Beziehung muss eine Beziehungstabelle (Join-Tabelle) eingeführt werden. Die Beziehungstabelle enthält zwei Fremdschlüssel, die jeweils auf eine Seite der Beziehung zeigen. In der viele-zu-viele-Beziehung in Abbildung 1.2 kann ein Student mehrere Dozenten (oder Professoren) haben und ein Dozent kann ebenso mehrere Studenten haben. Beziehungen werden in Kapitel 4.4 behandelt.

Abbildung 1.2: Viele-zu-viele-Beziehung in einer relationalen Datenbank

1.1.5 Graphennavigation

Über Objekte mit Java zu navigieren ist sehr leicht. Wenn beispielsweise auf alle Vor-lesungen eines Dozenten zugriffen werden soll, so wird einfach

aufgerufen. Zur Datenbank können bis dahin bereits zwei Zugriffe erfolgt sein. Einer für die Abfrage des Dozenten und ein weiterer für die Vorlesungen des Dozenten. Als Alter-native kann ein SQL-Join verwendet werden:

Damit reduziert sich die Anzahl der Datenbankzugriffe auf einen. Aber wie verhält sich der objekt-relationale Mapper? Wie kann verhindert werden, dass, wenn über alle Dozenten iteriert und dabei auf die Vorlesungen zugriffen wird, nicht jedesmal eine Abfrage an die Datenbank erfolgt (N+1-Problem)? Antworten auf diese Fragen werden in Kapitel 8 gegeben.

1.2 HibernateHibernate ist ein Open-Source-Produkt und beschreibt sich auf http://www.hibernate.orgals objekt-relationaler Persistenz- und Query-Service:

Hibernate is a powerful, high performance object/relational persistence and query service. Hiber-nate lets you develop persistent classes following object-oriented idiom- including association, inheritance, polymorphism, composition, and collections. Hibernate allows you to express queries in its own portable SQL extension (HQL), as well as in native SQL, or with an object-oriented Criteria and Example API.

dozent.getVorlesungen();

select * from DOZENT left outer join VORLESUNG where ...

<<Tabelle>> Student <<PK>>-id

<<Tabelle>> Student_Dozent <<FK>>-student_id <<FK>>-dozent_id

<<Tabelle>> Dozent <<PK>>-id

1 – Einleitung

20

Hibernate ist eine feste Größe unter den O/R1-Mappern und war mit Gavin King (Grün-der und Entwickler von Hibernate) auch maßgeblich an der Spezifikation der ersten Ver-sion der Java Persistence API (JPA)2 beteiligt. Der Erfolg von JPA 1.0, die vollständig durch Hibernate implementiert wird, ist sicherlich auch den fundierten Grundlagen von Hibernate zu verdanken.

1.3 Java Persistence APIIm Mai 2006 wurde das Final Release der EJB-3.0-Spezifikation (JSR-220) veröffentlicht. Ziel des JSR-220 war es, Java EE zu vereinfachen. Die Java Persistence API wurde als eigenständiger Teil der EJB-3.0-Spezifikation entwickelt und löste die Entity Beans ab.

Die wichtigsten Eigenschaften von JPA sind:

� die Entities sind einfache POJOs (Plain Old Java Objects)

� objektorientierte Klassenhierarchien mit Vererbung, Assoziationen, Polymorphismus usw. werden unterstützt

� die objektorientierte Abfragesprache Jave Persistence Query Language (JPQL)

� die API ist nicht nur in Java Enterprise Umgebungen (Applikationserver) einsetzbar, sondern auch in normalen Java Standard Umgebungen lauffähig

Die Java Persistence API 2.0 (JSR-317) wurde im Dezember 2009 als Final Release veröf-fentlicht. Im Verlauf des Buches werden die Neuerungen an den entsprechenden Stellen vorgestellt. Hier nur die wesentlichsten Punkte in Kürze:

� Collections von Basistypen

� eine Criteria API mit Metamodell

� ein Cache Interface

� Erweiterungen der JPQL Query API

� Unterstützung der Bean Validation API3

1. Abkürzung für objekt-relational.2. JSR-220 (Java Specifcation Request), http://jcp.org/en/jsr/detail?id=2203. Bean Validation API, http://jcp.org/en/jsr/summary?id=303

JPA mit Hibernate 21

2 Hibernate, Java und das Java Persistence API – Ein Überblick

2.1 Java 5 und höherMit Java 5 sind eine Reihe von hilfreichen und wichtigen Neuerungen in den Java-Stan-dard aufgenommen worden. In den beiden folgenden Abschnitten werden die zwei für Hibernate und JPA wichtigsten näher vorgestellt.

2.1.1 Annotations

Die in Java 5 neu hinzugekommenen Annotations bieten die Möglichkeit, Metadaten direkt im Sourcecode zu hinterlegen. Die Notwendigkeit für zusätzliche Dateien zur Speicherung der Metadaten wie z. B. XML- oder Property-Dateien entfällt somit. Die per Annotation hinterlegten Metadaten können unter anderem von Codegenerierungstools ausgelesen oder zur Laufzeit per Reflection abgefragt werden. Für den Entwickler haben Annotations den Vorteil, dass alle Informationen zentral im Sourcecode abgelegt sind und deren Zuordnung zum Sourcecode sofort ersichtlich ist.

In JPA und Hibernate können Metadaten, z. B. Mapping-Informationen, in Annotations angegeben werden. Die Verwendung von externen XML-Dateien oder von Javadoc in Verbindung mit XDoclet ist somit nicht mehr notwendig. Eine Übersicht der verfügbaren Annotations von JPA und Hibernate befindet sich im Anhang.

Verwendung von Annotations

Annotations werden direkt im Sourcecode vor dem zu markierenden Element eingefügt. Zur Kennzeichnung muss jeder Annotation ein @ vorangestellt werden. Zwischen dem @-Zeichen und dem Namen der Annotation sind Leerzeichen erlaubt. Parameter einer Annotation werden, wie bei Methoden auch, in Klammern an den Annotation-Namen angehängt.

Annotation-Parameter werden als Name-Wert-Paar angegeben, wobei die Reihenfolge der Parameter keine Rolle spielt (z. B. @MyAnnotation(para1=“hello“, para2=“world“) ). Hat die Annotation nur einen Parameter, kann der Name weggelassen werden. Bei parame-terlosen Annotations ist die Angabe der Klammern optional.

Annotations können sich auf alle wesentlichen Java-Elemente, wie Packages, Klassen, Interfaces, Enumerations, Methoden, Variablen und Methodenparameter, beziehen.

2 – Hibernate, Java und das Java Persistence API – Ein Überblick

22

Annotations in der Java SE 5.0

In der Java Standard Edition 5.0 wurden bereits sieben Annotations definiert. Dabei wird zwischen Standard-Annotation und Meta-Annotation unterschieden. Die Standard-Annotations sind zur normalen Verwendung beim Programmieren vorgesehen, wäh-rend die Meta-Annotations zur Definition neuer Annotation-Typen verwendet werden können.

Folgende Annotations stehen standardmäßig zur Verfügung:

� @Deprecated: Mittels dieser Annotation kennzeichnet man Methoden und Klassen, die nicht mehr verwendet werden sollen. Sie ist eine Alternative zur bisherigen Verfah-rensweise, veraltete Elemente über Javadoc-Kommentare zu markieren.

� @Override: Diese Annotation wird zur Markierung einer Methode verwendet. Der Com-piler stellt dann sicher, dass eine Methode einer Basisklasse überschrieben wird. Andern-falls wird eine Compiler-Fehlermeldung ausgegeben. Dadurch wird ein Überschreiben sichergestellt und Fehler aufgrund falsch geschriebener Methoden werden vermieden.

� @SuppressWarnings: Dient zur Unterdrückung von Compiler-Warnungen. Die War-nungen müssen als Parameter angegeben werden. Es werden alle Meldungen unter-drückt, die sich auf Elemente beziehen, die durch das markierte Element (z. B. eine Methode) eingeschlossen werden.

Listing 2.1 zeigt die Klasse AnnotationsHelloWorld. Die Methode sayHello() ist als veraltet markiert und löst bei Verwendung eine Compiler-Warnung aus. Die Markierung von toString() mit @Override stellt sicher, dass die Methode auch wirklich toString() aus Object überschreibt.

Als Meta-Annotations stehen folgende Elemente zur Verfügung:

� @Documented: Markierte Annotations werden automatisch bei der Verwendung von Javadoc, zur Erzeugung der Dokumentation, berücksichtigt.

public class AnnotationsHelloWorld {

@Deprecated public String sayHello() { return "Hello World"; }

@Override public String toString() { return "Hello World"; }}

Listing 2.1: Verwendung von Annotations

Java 5 und höher

JPA mit Hibernate 23

� @Inherited: Der Annotation-Typ wird automatisch vererbt und gilt automatisch auch für das entsprechende Element in allen abgeleiteten Subklassen.

� @Retention: Gibt an, wie lange die Annotation verfügbar ist. Es stehen folgende Werte zur Verfügung: � SOURCE: Die Informationen stehen nur bis zur Compile-Zeit zur Verfügung und

werden dann vom Compiler entfernt.� CLASS: Die Metadaten werden in den Class-Dateien abgespeichert, aber nicht

von der VM geladen. � RUNTIME: Annotations werden in der Class-Datei abgelegt und von der VM

geladen und stehen somit zur Auswertung per Reflection zur Verfügung.

� @Target: Mit Target wird definiert, welchen Elementen (Klasse, Methode, Parameter etc.) eine Annotation zugeordnet werden kann.

Eigene Annotations definieren

Listing 2.2 zeigt die Definition eines eigenen Annotation-Typs. Die Annotation MyAnnota-tion enthält drei Parameter: param1, param2 und counter. Für counter wurde ein Default-Wert von 0 definiert. Eine Angabe dieses Parameters bei Verwendung der Annotation ist somit optional.

Mit @Retention(RetentionPolicy.Source) wurde die Verfügbarkeit auf die Compile-Zeit eingeschränkt, ein Zugriff auf diese Annotation zur Laufzeit oder ein Auslesen aus der Class-Datei ist daher nicht möglich.

Durch Setzen von @Target({ElementType.METHOD, ElementType.TYPE}) wird festgelegt, dass MyAnnotation nur auf Methoden- und Klassenebene verwendet werden kann.

2.1.2 Generics

Die in der Java Standard Edition 5.0 neu eingeführten Generics erlauben die Abstraktion von Typen. Damit ist es möglich, Klassen und Methoden zu definieren, die generisch, also unabhängig von einem konkreten Typ, sind. Da JPA und Hibernate die Verwendung von Generics unterstützt, werden diese im folgenden Abschnitt näher erläutert.

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)public @interface MyAnnotation { String param1(); String param2(); int counter() default 0;}

Listing 2.2: Definition eines eigenen Annotation-Typs

2 – Hibernate, Java und das Java Persistence API – Ein Überblick

24

Verwendung von Generics

Ein gutes Beispiel ist das Collection Framework:

Bisher war der Cast auf Double in der letzten Zeile notwendig, da sonst ein Fehler durch den Compiler ausgegeben worden wäre, denn der Rückgabewert von get() ist Object.

Außerdem birgt diese Art der Verwendung von Collections das Risiko, dass ein Objekt in die Liste eingeführt wird, dessen Typ inkompatibel ist. Dies wird nicht durch den Com-piler erkannt, sondern tritt erst zur Laufzeit durch eine ClassCastException zutage.

Mithilfe der neuen generischen Collections lässt sich der obige Code folgendermaßen aus-drücken:

Mit List<Double> v wird angegeben, dass v eine Liste von Double ist. Der in spitzen Klammern angegebene Typ (hier Double) definiert den konkreten Typparameter, der für diese Liste verwendet wird. Die korrekte Verwendung dieser Liste wird durch den Com-piler sichergestellt. Daher ist das Einfügen eines unpassenden Typs nicht mehr möglich und ein Verstoß wird bereits zur Compile-Zeit erkannt. Der vorher notwendige Cast kann entfallen, denn der Rückgabewert von get() ist nun Double.

Falls mehrere Typparameter angegeben werden müssen, so werden sie durch Komma getrennt (z. B. Hashtable<Long, String>).

Die Verwendung von Generics verbessert somit die Lesbarkeit und hilft durch die erhöhte Typsicherheit, die Zuverlässigkeit des Codes zu erhöhen.

Einschränkungen und Besonderheiten

Bei der Verwendung von Generics muss man aber auch eine Reihe von Einschränkungen und Besonderheiten beachten, die unter anderem daher rühren, dass die Unterstützung von Generics nur auf Basis des Compilers umgesetzt wurde. Der VM selbst sind Gene-rics unbekannt, das heißt, die Typinformationen bei Generics stehen nur zur Compile-Zeit zur Verfügung.

Als Konsequenz hieraus liefert z. B. der Vergleich des Typs von Vector<String> und Vec-tor <Integer> true, denn zur Laufzeit gibt es nach wie vor nur den Typ Vector.

Außerdem gibt es zwischen z. B. List<Object> und List<String> keine Vererbungsbezie-hung. Das heißt, eine Liste von String ist somit keine Liste von Object.

List v = new Vector();v.add(new Double(1.0));Double d = (Double)v.get(0);

List<Double> v = new Vector<Double>();v.add(new Double(1.0));Double d = v.get(0);

Java 5 und höher

JPA mit Hibernate 25

Folgender Code führt zu einem Compile-Fehler:

Wildcards und Bounds

Um dieselben Möglichkeiten wie in dem bisherigen Collection-API zu haben, wie bei-spielsweise die Implementierung von Such- oder Sortieralgorithmen, die unabhängig von der verwendeten Collection sind, gibt es die so genannten Wildcards. Als Wildcard-zeichen wird ? verwendet. Ein Vector<?> steht für einen Vector mit beliebigem Inhalt. Folgender Code führt somit nicht mehr zu einem Compile-Fehler:

Allerdings gibt es auch bei der Verwendung von Wildcards einige Einschränkungen. So ist das Erzeugen einer Collection mit unbekanntem Typ genauso wenig möglich wie das Hin-zufügen eines Objekts zu einer solchen Collection, denn der Typ, für den ? steht, ist ja eben nicht bekannt.

Wildcards können darüber hinaus mit so genannten Bounds angegeben werden. Durch Angabe einer oberen Schranke mittels extends kann festgelegt werden, dass ein Typ vom angegebenen oder einem abgeleiteten Typ sein muss. Eine mittels super definierte untere Schranke legt fest, dass ein Typ vom angegebenen oder einem Supertyp sein muss.

Eigene generische Typen definieren

Generics sind nicht auf die Verwendung bestehender Klassen beschränkt. Auch eigene generische Typen können definiert werden.

Listing 2.3 zeigt die Definition der generischen Klasse MyGeneric, die zwei Typparameter (T und U) enthält. Die Typparameter können wie normale Typen bei der Definition der Klasse verwendet werden.

Vector<Object> v1 = new Vector<Object>();Vector<String> v2 = new Vector<String>();v1 = v2; //Compilefehler !

Vector<?> v1;Vector<String> v2 = new Vector<String>();v1 = v2;

List<? extends Number> l1; // Number oder Subtyp bspw. IntegerList<? super String> l2; // String oder Supertyp bspw. Object

public class MyGeneric<T, U> { private T key; private U value; public MyGeneric(T key, U value){ this.key = key; this.value = value; }

Listing 2.3: Definition einer eigenen generischen Klasse

2 – Hibernate, Java und das Java Persistence API – Ein Überblick

26

Eine Verwendung der Typparameter T und U in einem statischen Context ist allerdings nicht möglich. Folgende Definition innerhalb von MyGeneric würde zu einem Compile-Feh-ler führen:

Da statische Elemente nur einmal pro Klasse existieren, wäre eine typsichere Verwen-dung nicht garantiert, wenn zwei Instanzen einer generischen Klasse mit verschiedenen konkreten Typen initialisiert würden. Daher wird die Verwendung von statischen Ele-menten in Verbindung mit Typparametern durch den Compiler unterbunden.

Generische Methoden

Auch die Definition von generischen Methoden ist vorgesehen.

Listing 2.4 zeigt die Definition der generischen Methode sayHello(), die zwei Typpara-meter enthält. Im Gegensatz zu generischen Klassen muss bei der Verwendung generi-scher Methoden der Typparameter beim Aufruf nicht explizit angegeben werden, da er vom Compiler ermittelt wird.

public T getKey() { Return key; } public U getValue() { Return value; }}

private static T firstKey; // Compilefehler !

public class GenericMethod { public static <E, T> void sayHello(E pre, T post) { System.out.println(pre.toString() + " hello " + post.toString()); } public static void main(String[] args) { sayHello("generic", new StringBuffer("world")); }}

Listing 2.4: Definition und Verwendung einer generischen Methode

Listing 2.3: Definition einer eigenen generischen Klasse (Forts.)

Das Java Persistence API

JPA mit Hibernate 27

2.2 Das Java Persistence APIMit der EJB-3.0-Spezifikation wurde als Teil der Java Enterprise Edition 5.0 Platform ein neues Java Persistence API standardisiert. Es wurde im Rahmen des JSR 220 durch den Java Community Process von einer Expertengruppe erarbeitet, zu der neben Gavin King, dem Gründer von Hibernate, auch andere bekannte Persönlichkeiten aus der Java-Welt gehörten.

Das Ziel von JPA ist eine Standardisierung des Basis-API sowie der Metadaten eines objekt-relationalen Persistenzmechanismus für Java. Dabei handelt es sich nicht um ein fertiges Fra-mework, sondern lediglich um eine Spezifikation, die unter anderem von Hibernate imple-mentiert wird.

JPA ist nicht auf den Einsatz unter Java EE begrenzt. Im Gegensatz zu EJB 2.1 ist es auch in normalen Java-SE-Anwendungen außerhalb eines Java-EE-Containers einsetzbar. Die Spezifikation wurde durch Ideen und Zulieferungen anderer Persistenzframeworks wie Hibernate, TopLink und JDO bereichert. So ist es nicht weiter verwunderlich, dass JPA den gleichen Ansatz wie Hibernate verfolgt und die Entitäten als POJOs darstellt.

Zur Definition der Metadaten sind die in Java 5.0 neu hinzugekommenen Annotations vorgesehen, die direkt in den Entity-Klassen hinterlegt werden. Alternativ können natürlich weiterhin die bekannten XML- (Deployment-)Deskriptor-Dateien zur Angabe der Metadaten verwendet werden.

2.2.1 Entities

Die so genannten Entities sind leichtgewichtige, persistente Objekte und der zentrale Teil des JPA. Sie lösen die schwergewichtigen Entity Beans der älteren Java-EE-Versionen ab.

Für Entity-Klassen ist sowohl die Verwendung von abstrakten als auch konkreten Java-Klassen möglich. Dabei werden Vererbung, polymorphe Assoziationen und polymorphe Abfragen unterstützt.

Entity-Klassen müssen nicht von einer bestimmten Basisklasse abgeleitet sein. Somit können sie in einer eigenen Vererbungshierarchie verwendet werden. Entities und nor-male Java-Klassen können innerhalb einer Vererbungshierarchie beliebig kombiniert werden. Innerhalb der Entity-Klassen können die persistenten Attribute durch Annota-tions mit Mapping- und anderen Metadaten versehen werden.

Listing 2.5 zeigt eine einfache Entity-Klasse, in der die Mapping-Daten als Annotation definiert werden:

@Entitypublic class Book implements Serializable{ @Id private Long id; private String title; @ManyToMany private Set<Author> authors = new HashSet<Author>();

Listing 2.5: Eine einfache Entity-Klasse