Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Michael Plöd on Java Persistence API 2.0

Michael Plöd on Java Persistence API 2.0

More Decks by Enterprise Java User Group Austria

Other Decks in Technology

Transcript

  1. Java Persistence API 2.0 Überblick über die neuen Features Michael

    Plöd Quellen: JPA 2.0 Public Draft (JSR-317) Präsentation von Emmanuel Bernard bei JBUG München Bilder sind lizensiert von iStockphoto
  2. Michael Plöd • Architekt bei Senacor Technologies AG in Deutschland

    [email protected] • Arbeite gerade an JPA 2.0 Buch • Bin nicht Mitglied der JSR-317 Expert Group
  3. Abgeleitete Primärschlüssel • Primärschlüssel werden aus Many-To-One oder One-To-One Beziehungen

    abgeleitet • ID von Entity B (Parent) ist Primärschlüssel von Entity A <<Partent>> Kunde long kundeId <PK> String name <<Dependent>> Kreditkarte Long nummer <PK> Kunde kunde <PK> many-to-one one-to-one
  4. Abgeleitete Primärschlüssel <<Partent>> Kunde long kundeId <PK> String name <<Dependent>>

    Kreditkarte Long nummer <PK> Kunde kunde <PK> many-to-one one-to-one @Entity public class Kunde { @Id private long kundeId; private String name; ... } @Entity @IdClass(KundeId.class) public class Kreditkarte { @Id private Long nummer; @Id @ManyToOne private Kunde kunde; ... }
  5. Embeddables • Embeddables können Beziehungen haben • Beziehungen können bidirektional

    sein • Anpassung von Beziehungen mit @AssociationOverride • Embeddables können geschachtelt werden
  6. Code Beispiel: Embeddables @Entity public class Kunde { @Id private

    int id; private String nachname; ... @AssociationOverride( name="telefonNummern", joinTable=@JoinTable( name="TELEFON_NUMMERN", joinColumns=@JoinColumn(name="KUNDE"), inverseJoinColumns=@JoinColumn(name="TELEFON")) ) private KontaktDaten kontaktDaten; } @Embeddable public class KontaktDaten { @ManyToOne Adresse adresse; @OneToMany Set<Telefonnummer> telefonNummern; ... }
  7. Collections mit Value Objects • Collections mit Value Objects waren

    in JPA 1.0 nicht möglich • JPA 2.0 führt Collections mit Value Objects ein • Support gilt auch für Embeddables • @ElementCollection
  8. Code Beispiel: @ElementCollection @Entity public class Artikel { @Id private

    int id; ... @ElementCollection @CollectionTable(name="WEBTWO_TAGS") @Column(name="TAG") private Set<String> tags; } ARTIKEL ARTIKEL ARTIKEL ID TITLE ... WEBTWO_TAGS WEBTWO_TAGS ARTIKEL_ID TAG
  9. Code Beispiel: @ElementCollection @Entity public class Artikel { @Id private

    int id; ... @ElementCollection @CollectionTable(name="WEBTWO_TAGS") private Set<Tag> tags; } ARTIKEL ARTIKEL ARTIKEL ID TITLE ... WEBTWO_TAGS WEBTWO_TAGS WEBTWO_TAGS ARTIKEL_ID TAG ADDED @Embeddable public class Tag { private String tag; @Temporal(TIMESTAMP) private Date added; }
  10. Persistente Listen • JPA 1.0 konnte die Reihenfolge von Listen

    nicht persistieren • @OrderColumn spezifiziert die (nicht sichtbare) Sortierungs-Spalte @Entity public class Artikel { @Id private int id; private String titel; @OneToMany @OrderColumn(name="order") private List<Comment> comments; }
  11. Maps • Maps bestehen aus Keys und Values • Diese

    können in JPA 2.0 repräsentiert werden durch: • Embeddables • Entities • Basic Types
  12. Maps Key Value Basis Typ Embeddable Entity Ausnahmen @MapKeyColumn @ElementCollection

    Embeddable Defaults oder @AttributeOverride(s) @ElementCollection @MapKeyJoinColumn(s) @OneToMany @OneToOne @MapKey, wenn der Key selbst PK ist oder wenn Key Feld der Entität im Value ist @MapKeyClass, wenn keine Generics verwendet werden @MapKey, wenn der Key selbst PK ist oder wenn Key Feld der Entität im Value ist @MapKeyClass, wenn keine Generics verwendet werden
  13. Code Beispiel: Maps @Entity public class Artikel { ... @OneToMany(mappedBy="artikel")

    @MapKey(name="bildId") private Map<Integer, Bild> bilder; ... } @Entity public class Bild { ... @Id private Integer bildId @ManyToOne @JoinColumn(name="artikel_id") private Artikel artikel ... }
  14. Code Beispiel: Maps id: long ... rating: Map<Author, Integer> <<Entity>>

    RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author
  15. Code Beispiel: Maps id: long ... rating: Map<Author, Integer> <<Entity>>

    RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author
  16. Code Beispiel: Maps id: long ... rating: Map<Author, Integer> <<Entity>>

    RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  17. Code Beispiel: Maps id: long ... rating: Map<Author, Integer> <<Entity>>

    RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  18. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  19. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  20. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  21. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  22. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  23. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  24. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  25. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  26. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  27. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  28. Code Beispiel: Maps @Entity public class RecordReview { @Id int

    id; ... @ElementCollection @CollectionTable(name="RECORD_RATING", joinColumns=@JoinColumn(name="REVIEW_ID")) @Column(name="RATING") @MapKeyJoinColumn(name="AUTHOR_ID", referencedColumnName="ID") Map<Author, Integer> rating; ... } id: long ... rating: Map<Author, Integer> <<Entity>> RecordReview ID <PK> ... <<TABLE>> RECORD_REVIEW ID <PK> ... <<TABLE>> AUTHOR REVIEW_ID <FK> AUTHOR_ID <FK> RATING <<TABLE>> RECORD_RATING id: long ... <<Entity>> Author Text
  29. Orphan Removal • Orphan Removal bedeutet, dass Elemente, die aus

    einer Referenz entfernt werden, in der Datenbank gelöscht werden • Für One-To-Many und One-To-One Beziehungen • Wird über orphanRemoval=true aktiviert
  30. Code Beispiel: Orphan Removal @Entity public class Artikel { @Id

    private int id; ... @OneToMany(orphanRemoval=true) private Set<Comment> kommentar; }
  31. Zugriffsart • Klassen können unterschiedliche Zugriffsarten haben: • Property-Access •

    Field-Access • Platzierung von Annotation bestimmt Default • Ausnahmen werden mit @Access spezifiziert
  32. Code Beispiel: @Access @Entity @Access(FIELD) public class Artikel { @Id

    private int id; public String titel; public String text; ... @Access(PROPERTY) public String getText() { return text; } public void setText(String text) { this.text = text; } }
  33. Neuerungen in JPQL • Unterstützung für neue Mappings (Maps, usw)

    • Nicht polymorphe Abfragen • Bedingungen mit Case when else when • COALESCE Unterstützung • Collections können für IN Parameter übergeben werden
  34. Code Beispiel: JPQL SELECT a.titel, CASE TYPE(a) WHEN Interview THEN

    'Interview' WHEN RecordReview THEN 'CD Kritik' WHEN ShowReview THEN 'Konzert Kritik' ELSE 'Sonstiges' END FROM Artikel a WHERE a.author.name = 'Michael'
  35. Code Beispiel: JPQL SELECT a.titel, CASE TYPE(a) WHEN Interview THEN

    'Interview' WHEN RecordReview THEN 'CD Kritik' WHEN ShowReview THEN 'Konzert Kritik' ELSE 'Sonstiges' END FROM Artikel a WHERE a.author.name = 'Michael' SELECT a FROM Artikel a WHERE TYPE(a) IN (RecordReview, ShowReview)
  36. Code Beispiel: JPQL SELECT a.titel, CASE TYPE(a) WHEN Interview THEN

    'Interview' WHEN RecordReview THEN 'CD Kritik' WHEN ShowReview THEN 'Konzert Kritik' ELSE 'Sonstiges' END FROM Artikel a WHERE a.author.name = 'Michael' SELECT a FROM Artikel a WHERE TYPE(a) IN (RecordReview, ShowReview) class Artikel { Map<ImageMeta, Image> image; ...} SELECT a.titel FROM Artikel a JOIN a.image i WHERE KEY(i).pfad = :pfad
  37. Criteria API • Criteria bieten API getriebene Abfragen • Populäres

    Feature von Hibernate und OO Datenbanken • Criteria sind type-safe • Perfekt für dynamisch erzeugte Abfragen
  38. Erstellen von Criteria Queries EntityManager QueryBuilder QueryDefinition Ausgangs Basis Hilfs

    Objekt Abfrage entityManager.getQueryBuilder().createQueryDefinition()
  39. Query Roots Root sind Domänen Objekte, von denen aus andere

    Objekte über die Abfrage erreicht werden EntityManager em; QueryBuilder qb = em.getQueryBuilder(); QueryDefinition def = qb.createQueryDefinition(); //select a from Artikel DomainObject artikel = def.addRoot(Artikel.class);
  40. Einschränkung Einschränkungen der Ergebnismenge werden mit QueryDefinition#where(..) spezifiziert DomainObject artikel

    = q.addRoot(Artikel.class); q.where(artikel.get("titel").equal("EJUG-Days") .and(artikel.get("autor").equal("Michael")) ); SELECT a FROM Artikel a WHERE a.titel = "EJUG-Days" AND a.author = "Michael"
  41. Joins • Joins werden über folgende Methoden von DomainObject formuliert:

    • join() • leftJoin() DomainObject artikel= q.addRoot(Artikel.class); DomainObject b = artikel.join("comments").join("benutzer"); b.where(b.get("name").equal("mike")); SELECT a FROM Artikel a JOIN a.comments c JOIN c.benutzer b WHERE b.name = „mike“
  42. Fetch Joins • Fetch Joins werden über folgende Methoden von

    DomainObject formuliert: • joinFetch() • leftJoinFetch() DomainObject artikel= q.addRoot(Artikel.class); DomainObject b = artikel.leftJoinFetch("comments"); SELECT a FROM Artikel a LEFT JOIN FETCH a.comments c
  43. Selektion Selektion der abgefragten Attribute erfolgt mit QueryDefinition#select(...) DomainObject artikel

    = qb.createQueryDefinition(Artikel.class); DomainObject bild = item.join("bilder"); artikel.select(artikel.get("titel"), bild) .where(bild.key().like("U2")); SELECT a.titel, bild FROM Artikel a JOIN a.bilder b WHERE KEY(b) LIKE "U2"
  44. Geschachtelte Abfragen Subqueries werden über eine neue QueryDefinition erstellt DomainObject

    guteCD = qb.createQueryDefinition(Record.class); DomainObject cd = qb.createQueryDefinition(Record.class); guteCD.where(guteCD.get("rating") .greaterThan(cd.select(cd.get("rating").avg()))); SELECT guteCD FROM Record guteCD WHERE guteCD.rating > (SELECT AVG(c.rating) FROM Record c)
  45. Group By und Having Group By und Having werden über

    die Methoden QueryDefinition#groupBy und #having angegeben QueryDefinition q = qb.createQueryDefinition(); DomainObject cd = q.addRoot(Record.class); q.select(cd.get("status"), cd.get("rating").avg(), cd.count()) .groupBy(cd.get("status")) .having(q.get("status").in(1, 2)); SELECT cd.status, AVG(cd.rating), COUNT(cd) FROM Record cd GROUP BY cd.status HAVING cd.status IN (1, 2)
  46. Sortierung von Ergebnissen Abfrage Ergebnisse werden über QueryDefinition#orderBy sortiert QueryDefinition

    q = qb.createQueryDefinition(); DomainObject artikel = q.addRoot(Artikel.class); q.orderBy(artikel.get("datum").desc()); SELECT a FROM Artikel a ORDER BY a.datum DESC
  47. Ausführen von Abfragen Zum Ausführen einer Abfrage wird die QueryDefinition

    der Methode createQuery des EntityManagers übergeben EntityManager em = ...; QueryBuilder qb = em.getQueryBuilder(); QueryDefinition q = qb.createQueryDefinition(); DomainObject artikel = q.addRoot(Artikel.class); q.orderBy(artikel.get("datum").desc()); Query query = entityManager.createQuery(q); query.getResultList();
  48. In der finalen Version von JPA 2.0 wird es sicher

    noch Änderungen bei Criteria Queries geben !
  49. Spezifizieren von Timeouts • Hint: javax.persistence.lock.timeout • Konfiguration über •

    query.setLockMode(..) • Property in Persistence.createEntityManagerFactory(..) • Properties Element von persistence.xml
  50. Caching Second Level Cache EntityManager First Level Cache EntityManager First

    Level Cache EntityManager First Level Cache EntityManager First Level Cache Datenbank
  51. First Level Cache • First Level Cache des EntityManagers kann

    nicht deaktiviert werden • Mit clear() bzw. clear(Object o) können Elemente aus Persistenz Kontext entfernt werden • Wichtig für Batch Jobs!
  52. Grundregeln • ORM ist kein Batch Tool! • Bei Massen-Verarbeitung

    regelmässig flushen und clearen! • JDBC Batch-Size anpassen for ( int i=0; i<100000; i++ ) { Konto konto = new Konto(...); em.persist(konto); if ( i % 50 == 0 ) { em.flush(); em.clear(); } }
  53. Second Level Cache • Implementierung ist abhängig vom Hersteller •

    JPA 2.0 bietet nur ein Basis Interface javax.persistence.Cache public boolean contains(Class cls, Object primaryKey); public void evict(Class cls, Object primaryKey); public void evict(Class cls); public void evictAll();
  54. Hints & Parameter • Standardisierte Hints: • javax.persistence.lock.timeout • javax.persistence.query.timeout

    • Standardisierte Parameter: • javax.persistence.jdbc.driver • javax.persistence.jdbc.url • javax.persistence.jdbc.user • javax.persistence.jdbc.password