JPA - Java Persistence API
Thomas Wöhlke
ObjectCode GmbH
12.03.2009
JPA: Agenda
© 2009 ObjectCode GmbH
Domain Object Model
© 2009 ObjectCode GmbH
Object-Relational Mapping
Analogie: OO  RDB
 Klasse  Tabelle
 Objekt  Zeile
 Variable Spalte
 Wert  Feld
Domain Object Modell = ERD ?
© 2009 ObjectCode GmbH
O/R Impedance Mismatch
© 2009 ObjectCode GmbH
O/R Impedance Mismatch
© 2009 ObjectCode GmbH
Domain Object Model: GLE
© 2009 ObjectCode GmbH
... und die Physik?
• v(Harddisk) << v(RAM)
• CPU 99% idle
• Process 99% IO_WAIT
• Page Impressions  SQL-Requests?
© 2009 ObjectCode GmbH
Anno Domini 2004...
© 2009 ObjectCode GmbH
© 2004-2005 TheServerside.com
Hibernate
Mapping von POJO‘s:
2. Java Bean API
3. Collection API (Generics)
4. Mapping:
XML oder Hibernate-Annotations
Hibernate ist ein JPA-Vendor:
 Hibernate-Core
 Hibernate-Annotations
 Hibernate Entity Manager
© 2009 ObjectCode GmbH
Von Hibernate nach JPA
© 2009 ObjectCode GmbH
JPA im JEE-Stack
© 2009 ObjectCode GmbH
persistence.xml (Java EE)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="JPM_DB">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/JpmDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<!-- These are the default for JBoss EJB3, but not for HEM: -->
<property name="hibernate.cache.provider_class"
value="org.hibernate.cache.HashtableCacheProvider"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
</properties>
</persistence-unit>
</persistence>
© 2009 ObjectCode GmbH
persistence.xml (Java SE)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="JPM_DB">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.woehlke.projecteering.kernel.calendar.pao.Day</class>
<class>org.woehlke.projecteering.kernel.minutes.pao.Event</class>
<class>org.woehlke.projecteering.kernel.minutes.pao.Minutes</class>
<class>org.woehlke.projecteering.kernel.minutes.pao.MinutesItem</class>
<class>org.woehlke.projecteering.kernel.projects.pao.Project</class>
<class>org.woehlke.projecteering.kernel.projects.pao.ProjectCategory</class>
<class>org.woehlke.projecteering.kernel.timerecording.pao.TimeRecordingItem</class>
<class>org.woehlke.projecteering.kernel.userrights.pao.Company</class>
<class>org.woehlke.projecteering.kernel.userrights.pao.Team</class>
<class>org.woehlke.projecteering.kernel.userrights.pao.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.generate_statistics" value="true"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="jpm"/>
<property name="hibernate.connection.password" value="jpmpwd"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpm"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
© 2009 ObjectCode GmbH
Mapping der Klassen 1
public class Customer extends Person {
@OneToMany(mappedBy=“purchaser”) Set<Order> orders =
new HashSet<Order>();
protected Customer() { } // for loading from db
public Customer(String fname, String lname) {
super(fname, lname);
}
public void addOrder(Order o) { orders.add(o); }
public Set<Order> getOrders() { return orders; }
}
© 2009 ObjectCode GmbH
Mapping der Klassen 2
@Entity
@Table(name=“PRODUCTS”)
public class Product {
@Id @GeneratedValue
@Column(name=“PRODUCT_PK”)
long id;
@Version int oplock; // column defaults to “OPLOCK”
String name; // column defaults to “NAME”
@ManyToOne
@JoinColumn(name=“SUPP_FK”,
referencedColumnName=“SUPP_PK”)
Supplier supplier;
...
}
© 2009 ObjectCode GmbH
Mapping der Assoziationen
Kardinalität:
 1:1  OneToOne
 1:n  OneToMany
 n:m  ManyToMany
Richtung:
 1:n -> OneToMany
 N:1 <- ManyToOne
Sichtbarkeit:
 Unidirektional ->
 Bidirektional <->
© 2009 ObjectCode GmbH
Mapping der Vererbung
2. Eine Tabelle pro Klassen-Hierarchie
3. Eine Tabelle pro konkrete Klasse
4. Eine Tabelle pro Subklasse
5. Non-Entity Vererbung
6. Keine Vererbung: Embbeding
© 2009 ObjectCode GmbH
Mapping der Vererbung?
© 2009 ObjectCode GmbH
Einsatz von JPA im JBoss/EJB3
@Stateless
public class MinutesItemDao extends BaseDao<MinutesItem> implements
IMinutesItemDao {
@PersistenceContext(unitName = "JPM_DB")
private EntityManager entityManager;
public MinutesItem findById(Long id) {
return entityManager.find(MinutesItem.class,id);
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
© 2009 ObjectCode GmbH
Einsatz von JPA in Spring/Tomcat
@Transactional
public class MinutesDao extends BaseDao<Minutes> implements
IMinutesDao {
public Minutes findById(Long id) {
return jpaTemplate.find(Minutes.class,id);
}
}
© 2009 ObjectCode GmbH
EJB-QL
Query q = em.createQuery(“select c from Customer c where c.firstName
= :fname order by c.lastName”);
q.setParameter(“fname”, “Joe”);
q.setFirstResult(20);
q.setMaxResults(10);
List<Customer> customers = (List<Customer>) q.getResultList();
// all orders, as a named query
@Entity
@NamedQuery(name=“Order:findAllOrders”,
query=“select o from Order o”);
public class Order { ... }
Query q = em.createNamedQuery(“Order:findAllOrders”);
© 2009 ObjectCode GmbH
Lebenszyklus Persistente Objekte
2. Neu, transient (@Id id == null)
3. Persistent (@Id id != null)
4. Detached:
– Wie persistent (@Id id!= null)
– Jedoch ausserhalb des EntityManager Kontext
– Lazy Loading nicht möglich!
– Änderungen in DB sichern mit merge
© 2009 ObjectCode GmbH
EJB-QL
// all people, via a custom SQL statement
Query q = em.createNativeQuery(“SELECT ID, VERSION, SUBCLASS,
FIRSTNAME, LASTNAME FROM PERSON”, Person.class);
List<Person> people = (List<Person>) q.getResultList();
// single-result aggregate: average order total price
Query q = em.createQuery(“select avg(i.price) from Item i”);
Number avgPrice = (Number) q.getSingleResult();
// traverse to-many relations
Query q = em.createQuery(“select o from Order o left join o.items li where
li.price > :price”);
q.setParameter(“price”, 1000);
List<Order> orders = (List<Order>) q.getResultList();
© 2009 ObjectCode GmbH
Lazy Loading
• Supplier s = order.getItem().getProduct().getSupplier();
• Bei Aufruf eines Getters wird Objekt aus DB-Zeile nachgeladen.
• Ohne Lazy Loading muss komplettes Objekt-Netz geladen werden.
• Struktur des Objekt-Netzes variiert je nach Web-View
© 2009 ObjectCode GmbH
DAO und „Unit of Work“
© 2009 ObjectCode GmbH
Ausblick: Seam
• Kern-Entwickler von Hibernate sind nun im
Seam-Projekt
• O/R-Mapping von EJB3/JPA auch für die
Webapplikation
• OO im Datenbankbackend durch ORM
• OO im Webfrontend durch JSF
• Im Conversation-Scope ist Lazy-Loading möglich.
• Detached Objects können für die Webview
verwendet werden: Kein DTO-Antipattern
© 2009 ObjectCode GmbH
RTFM: http://www.hibernate.org/
O‘Reilly: Enterprise JavaBeans 3.0
Manning: EJB3 in Action
Manning: Hibernate in Action
Literatur
© 2009 ObjectCode GmbH
FRAGEN? Fragen!
... Vielen Dank
für die Aufmerksamkeit
© 2009 ObjectCode GmbH

JPA - Java Persistence API

  • 1.
    JPA - JavaPersistence API Thomas Wöhlke ObjectCode GmbH 12.03.2009
  • 2.
    JPA: Agenda © 2009ObjectCode GmbH
  • 3.
    Domain Object Model ©2009 ObjectCode GmbH
  • 4.
    Object-Relational Mapping Analogie: OO RDB  Klasse  Tabelle  Objekt  Zeile  Variable Spalte  Wert  Feld Domain Object Modell = ERD ? © 2009 ObjectCode GmbH
  • 5.
    O/R Impedance Mismatch ©2009 ObjectCode GmbH
  • 6.
    O/R Impedance Mismatch ©2009 ObjectCode GmbH
  • 7.
    Domain Object Model:GLE © 2009 ObjectCode GmbH
  • 8.
    ... und diePhysik? • v(Harddisk) << v(RAM) • CPU 99% idle • Process 99% IO_WAIT • Page Impressions  SQL-Requests? © 2009 ObjectCode GmbH
  • 9.
    Anno Domini 2004... ©2009 ObjectCode GmbH © 2004-2005 TheServerside.com
  • 10.
    Hibernate Mapping von POJO‘s: 2.Java Bean API 3. Collection API (Generics) 4. Mapping: XML oder Hibernate-Annotations Hibernate ist ein JPA-Vendor:  Hibernate-Core  Hibernate-Annotations  Hibernate Entity Manager © 2009 ObjectCode GmbH
  • 11.
    Von Hibernate nachJPA © 2009 ObjectCode GmbH
  • 12.
    JPA im JEE-Stack ©2009 ObjectCode GmbH
  • 13.
    persistence.xml (Java EE) <?xmlversion="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="JPM_DB"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/JpmDS</jta-data-source> <properties> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <property name="hibernate.show_sql" value="true"/> <!-- These are the default for JBoss EJB3, but not for HEM: --> <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/> </properties> </persistence-unit> </persistence> © 2009 ObjectCode GmbH
  • 14.
    persistence.xml (Java SE) <?xmlversion="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="JPM_DB"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>org.woehlke.projecteering.kernel.calendar.pao.Day</class> <class>org.woehlke.projecteering.kernel.minutes.pao.Event</class> <class>org.woehlke.projecteering.kernel.minutes.pao.Minutes</class> <class>org.woehlke.projecteering.kernel.minutes.pao.MinutesItem</class> <class>org.woehlke.projecteering.kernel.projects.pao.Project</class> <class>org.woehlke.projecteering.kernel.projects.pao.ProjectCategory</class> <class>org.woehlke.projecteering.kernel.timerecording.pao.TimeRecordingItem</class> <class>org.woehlke.projecteering.kernel.userrights.pao.Company</class> <class>org.woehlke.projecteering.kernel.userrights.pao.Team</class> <class>org.woehlke.projecteering.kernel.userrights.pao.User</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.generate_statistics" value="true"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.connection.username" value="jpm"/> <property name="hibernate.connection.password" value="jpmpwd"/> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpm"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> </properties> </persistence-unit> </persistence> © 2009 ObjectCode GmbH
  • 15.
    Mapping der Klassen1 public class Customer extends Person { @OneToMany(mappedBy=“purchaser”) Set<Order> orders = new HashSet<Order>(); protected Customer() { } // for loading from db public Customer(String fname, String lname) { super(fname, lname); } public void addOrder(Order o) { orders.add(o); } public Set<Order> getOrders() { return orders; } } © 2009 ObjectCode GmbH
  • 16.
    Mapping der Klassen2 @Entity @Table(name=“PRODUCTS”) public class Product { @Id @GeneratedValue @Column(name=“PRODUCT_PK”) long id; @Version int oplock; // column defaults to “OPLOCK” String name; // column defaults to “NAME” @ManyToOne @JoinColumn(name=“SUPP_FK”, referencedColumnName=“SUPP_PK”) Supplier supplier; ... } © 2009 ObjectCode GmbH
  • 17.
    Mapping der Assoziationen Kardinalität: 1:1  OneToOne  1:n  OneToMany  n:m  ManyToMany Richtung:  1:n -> OneToMany  N:1 <- ManyToOne Sichtbarkeit:  Unidirektional ->  Bidirektional <-> © 2009 ObjectCode GmbH
  • 18.
    Mapping der Vererbung 2.Eine Tabelle pro Klassen-Hierarchie 3. Eine Tabelle pro konkrete Klasse 4. Eine Tabelle pro Subklasse 5. Non-Entity Vererbung 6. Keine Vererbung: Embbeding © 2009 ObjectCode GmbH
  • 19.
    Mapping der Vererbung? ©2009 ObjectCode GmbH
  • 20.
    Einsatz von JPAim JBoss/EJB3 @Stateless public class MinutesItemDao extends BaseDao<MinutesItem> implements IMinutesItemDao { @PersistenceContext(unitName = "JPM_DB") private EntityManager entityManager; public MinutesItem findById(Long id) { return entityManager.find(MinutesItem.class,id); } public EntityManager getEntityManager() { return entityManager; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } } © 2009 ObjectCode GmbH
  • 21.
    Einsatz von JPAin Spring/Tomcat @Transactional public class MinutesDao extends BaseDao<Minutes> implements IMinutesDao { public Minutes findById(Long id) { return jpaTemplate.find(Minutes.class,id); } } © 2009 ObjectCode GmbH
  • 22.
    EJB-QL Query q =em.createQuery(“select c from Customer c where c.firstName = :fname order by c.lastName”); q.setParameter(“fname”, “Joe”); q.setFirstResult(20); q.setMaxResults(10); List<Customer> customers = (List<Customer>) q.getResultList(); // all orders, as a named query @Entity @NamedQuery(name=“Order:findAllOrders”, query=“select o from Order o”); public class Order { ... } Query q = em.createNamedQuery(“Order:findAllOrders”); © 2009 ObjectCode GmbH
  • 23.
    Lebenszyklus Persistente Objekte 2.Neu, transient (@Id id == null) 3. Persistent (@Id id != null) 4. Detached: – Wie persistent (@Id id!= null) – Jedoch ausserhalb des EntityManager Kontext – Lazy Loading nicht möglich! – Änderungen in DB sichern mit merge © 2009 ObjectCode GmbH
  • 24.
    EJB-QL // all people,via a custom SQL statement Query q = em.createNativeQuery(“SELECT ID, VERSION, SUBCLASS, FIRSTNAME, LASTNAME FROM PERSON”, Person.class); List<Person> people = (List<Person>) q.getResultList(); // single-result aggregate: average order total price Query q = em.createQuery(“select avg(i.price) from Item i”); Number avgPrice = (Number) q.getSingleResult(); // traverse to-many relations Query q = em.createQuery(“select o from Order o left join o.items li where li.price > :price”); q.setParameter(“price”, 1000); List<Order> orders = (List<Order>) q.getResultList(); © 2009 ObjectCode GmbH
  • 25.
    Lazy Loading • Suppliers = order.getItem().getProduct().getSupplier(); • Bei Aufruf eines Getters wird Objekt aus DB-Zeile nachgeladen. • Ohne Lazy Loading muss komplettes Objekt-Netz geladen werden. • Struktur des Objekt-Netzes variiert je nach Web-View © 2009 ObjectCode GmbH
  • 26.
    DAO und „Unitof Work“ © 2009 ObjectCode GmbH
  • 27.
    Ausblick: Seam • Kern-Entwicklervon Hibernate sind nun im Seam-Projekt • O/R-Mapping von EJB3/JPA auch für die Webapplikation • OO im Datenbankbackend durch ORM • OO im Webfrontend durch JSF • Im Conversation-Scope ist Lazy-Loading möglich. • Detached Objects können für die Webview verwendet werden: Kein DTO-Antipattern © 2009 ObjectCode GmbH
  • 28.
    RTFM: http://www.hibernate.org/ O‘Reilly: EnterpriseJavaBeans 3.0 Manning: EJB3 in Action Manning: Hibernate in Action Literatur © 2009 ObjectCode GmbH
  • 29.
    FRAGEN? Fragen! ... VielenDank für die Aufmerksamkeit © 2009 ObjectCode GmbH