Präsentation zum Vortrag von Dirk Weil (GEDOPLAN, http://www.gedoplan.de) auf der W-JAX 2012:
Der überwiegende Teil von Unternehmensanwendungen nutzt O/R-Mapper zum Zugriff auf Datenbanken. Reicht dafür der Standard JPA 2.0 oder braucht man zwingend spezielle Eigenschaften von Hibernate/EclipseLink/OpenJPA? Soll man transaktionsgebunden oder konversationsorientiert arbeiten? Welche Neuerungen sind für JPA 2.1 geplant? Dieser Talk beantwortet die Fragen anhand diverser Beispiele aus der Praxis.
5. Java Persistence in EE-Anwendungen
• The CDI way: public class EntityManagerProducer {
@PersistenceContext(unitName = "beantrial")
@Produces
EntityManager entityManager;
public class PersonRepository {
@Inject
EntityManager entityManager; public class ProjektRepository {
@Inject
EntityManager entityManager;
public class FirmaRepository {
@Inject
EntityManager entityManager;
5 Java Persistence in Action dirk.weil@gedoplan.de
6. Entity Manager Lifecycle
• EM-Lebensdauer Entity-Management-Zeit
– Entities werden detached
– Nachladen von Lazy-Werten etc. nicht mehr möglich
alle evtl. benötigten Werte müssen geladen sein
• Remote-Anwendung (Swing, Java FX, …)
– Entities im Client sind stets detached
• Web-Anwendung (JSF, …)
– Render-Phase, Folgerequests?
6 Java Persistence in Action dirk.weil@gedoplan.de
7. Entity Manager Lifecycle
<h:dataTable value="#{personModel.personen}" var="person">
…
<h:… value="#{person.hobbies}" />
…
LazyLoad
Exception
?
@Entity
public class Person {
@ElementCollection(fetch = FetchType.LAZY)
private List<String> hobbies;
@Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
7 Java Persistence in Action dirk.weil@gedoplan.de
8. Entity Manager Lifecycle
• EM-Optionen:
– Transaction-scoped
– (Extended)*
verschiedene
– Application-managed Kombinationen
möglich
• Patterns
– Eager Loading
– Open Entity Manager in View
– Conversational Entity Manager
*nur Stateful EJBs – nicht weiter betrachtet
8 Java Persistence in Action dirk.weil@gedoplan.de
9. Transaction-scoped Entity Manager
• Standard für container-managed Entity Manager
@Transactional
public class PersonRepository {
@Inject
EntityManager entityManager;
public void persist(Person entity) { … }
public List<Person> findAll() { … }
public class EntityManagerProducer {
@PersistenceContext(unitName = "beantrial")
@Produces
EntityManager entityManager;
9 Java Persistence in Action dirk.weil@gedoplan.de
10. Transaction-scoped Entity Manager
• Start: Erste Nutzung des EM in einer TX
• Ende: TX-Ende alle Entities werden detached
• TX-Steuerung
– per CDI Interceptor @Transactional
– per EJB
– mittels UserTransaction
– häufig für (Teil-)Geschäftsprozesse
(nur für CRUD wäre ein Antipattern)
10 Java Persistence in Action dirk.weil@gedoplan.de
11. Transaction-scoped Entity Manager
<h:dataTable value="#{personModel.personen}" …>
View …
<h:… value="#{person.hobbies}" />
detached
Model @Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
TX
Service @Transactional
public class PersonRepository {
managed
public List<Person> findAll() { … }
DB
11 Java Persistence in Action dirk.weil@gedoplan.de
12. Transaction-scoped Entity Manager
• Eager Loading nötig
– deklarativ @ElementCollection(fetch = FetchType.EAGER)
private List<String> hobbies;
– oder durch expliziten public void loadLazyAttributes() {
Zugriff this.hobbies.size();
12 Java Persistence in Action dirk.weil@gedoplan.de
13. Transaction-scoped Entity Manager
• Code Browsing:
Personenverwaltung mit detached Entities
(Download: www.gedoplan.de Blog
13 Java Persistence in Action dirk.weil@gedoplan.de
14. Transaction-scoped Entity Manager
• Alternative: Transaction per Request
TX
<h:dataTable value="#{personModel.personen}" …>
View …
<h:… value="#{person.hobbies}" />
Model @Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
…
14 Java Persistence in Action dirk.weil@gedoplan.de
15. Transaction-scoped Entity Manager
• Transaction per Request
– mittels Servlet Filter
– mittels JSF Phase Listener
– Seam Transaction / Seam Faces
Achtung: Per Default aktiv !
(Abschalten: Siehe www.gedoplan.de Blog)
15 Java Persistence in Action dirk.weil@gedoplan.de
16. Transaction-scoped Entity Manager
• Einfaches Verfahren
• Eager Loading
– ist aufwändig
– hebelt Lazy-Optimierungen aus
• TX per Request
– durchbricht 'normale' Architektur
– nicht für Multi-Request-Fälle geeignet
16 Java Persistence in Action dirk.weil@gedoplan.de
17. Application-managed Entity Manager
• Nutzung von EntityManagerFactory
• Lifecycle wird von Anwendung bestimmt
public class EntityManagerProducer {
@PersistenceUnit(unitName = "beantrial")
EntityManagerFactory entityManagerFactory;
@Produces
public EntityManager createEntityManager() {
return this.entityManagerFactory.createEntityManager();
}
public void closeEntityManager(@Disposes @Any EntityManager em) {
if (em.isOpen())
em.close();
}
17 Java Persistence in Action dirk.weil@gedoplan.de
18. Application-managed Entity Manager
• persist, merge, remove auch ohne TX erlaubt
• Änderungen werden erst durch Commit abgelegt
• Entity Manager nicht automatisch TX-gebunden
@Transactional
public void saveAll() {
this.entityManager.joinTransaction();
}
18 Java Persistence in Action dirk.weil@gedoplan.de
19. Request-scoped Entity Manager
@Produces
• Request @RequestScoped
Scope public EntityManager createEntityManager() {
= Open Entity Manager in View
View <h:dataTable value="#{personModel.personen}" …>
Entity Manager
…
<h:… value="#{person.hobbies}" />
Model @Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
TX
Service @Transactional
public class PersonRepository {
public void saveAll() { … }
DB
19 Java Persistence in Action dirk.weil@gedoplan.de
20. Conversation-scoped Entity Manager
• Conversational @Produces
@ConversationScoped
Entity Manager public EntityManager createEntityManager() {
Request 1
EM
Request 2
Conversation.begin()
Request 3
EM
Request 4
Conversation.end()
20 Java Persistence in Action dirk.weil@gedoplan.de
21. Conversation-scoped Entity Manager
• ABER:
– Conversation Scope ist passivating
– Objekte in ihm müssen serialisierbar sein
– EntityManager nicht notwendigerweise
Serializable
• Abhilfe: Serializable-Wrapper
21 Java Persistence in Action dirk.weil@gedoplan.de
22. Conversation-scoped Entity Manager
• Serializable-Wrapper:
@Produces
@ConversationScoped
public EntityManager createEntityManager() {
EntityManager em = entityManagerFactory.createEntityManager();
if (!(em instanceof Serializable)) {
ClassLoader loader = em.getClass().getClassLoader();
Class<?>[] ifs = { EntityManager.class, Serializable.class };
EMInvocationHandler handler = new EMInvocationHandler(em);
em = (EntityManager) Proxy.newProxyInstance(loader, if, handler);
}
return em;
}
22 Java Persistence in Action dirk.weil@gedoplan.de
23. Conversation-scoped Entity Manager
• Serializable-Wrapper:
class EMInvocationHandler implements InvocationHandler, Serializable {
private transient EntityManager em;
public EntityManagerInvocationHandler(EntityManager em) {
this.em = em;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (this.entityManager == null)
throw new IllegalStateException("EntityManager is null");
return method.invoke(this.em, args);
}
}
23 Java Persistence in Action dirk.weil@gedoplan.de
24. Conversation-scoped Entity Manager
• Serializable-Wrapper:
– Prinzip Hoffnung:
Wahrscheinlich keine Passivierung;
wenn doch, ordentliche Fehlermeldung.
– Ungeeignet für Replikation
24 Java Persistence in Action dirk.weil@gedoplan.de
25. Conversation-scoped Entity Manager
• Code Browsing:
Personenverwaltung mit attached Entities
(Download: www.gedoplan.de Blog
25 Java Persistence in Action dirk.weil@gedoplan.de
26. SQL-Zugriffe im Beispiel
Aktion TX-scoped EM Conv-scoped EM
Anzeige aller Personen
SELECT ID, ... FROM PERSON dito
Auswahl einer Person zum Editieren
SELECT ID, ... FROM PERSON
WHERE (ID = ?)
SELECT TEL, ... FROM PERSON_TEL dito
WHERE (PERSON_TEL.Person_ID = ?)
SELECT HOBBY, ... FROM PERSON_HOBBY
WHERE (PERSON_HOBBY.Person_ID = ?)
26 Java Persistence in Action dirk.weil@gedoplan.de
27. SQL-Zugriffe im Beispiel
Aktion TX-scoped EM Conv-scoped EM
Ändern des Vornamens und Speichern der Person
SELECT ID, ... FROM PERSON
WHERE (ID = ?)
SELECT TEL, ... FROM PERSON_TEL
WHERE (PERSON_TEL.Person_ID = ?)
SELECT HOBBY, ... FROM PERSON_HOBBY
WHERE (PERSON_HOBBY.Person_ID = ?)
UPDATE PERSON SET VORNAME = ? dito
WHERE (ID = ?)
27 Java Persistence in Action dirk.weil@gedoplan.de
28. TX- oder Conversation-scoped?
• Transaction-scoped EM
einfaches Vorgehen
speichert nur das, was explizit übergeben wird
• Conversation-scoped EM
vermeidet Lazy-Load-Effekte im Web-Anwendungen
erzeugt weniger DB-Zugriffe
speichert immer alle Änderungen
benötigt mehr Speicher
funktioniert nicht im Cluster oder für Remote-Clients
28 Java Persistence in Action dirk.weil@gedoplan.de
29. JPA 2.1 – What's coming?
• Query-Erweiterungen
– ON: Join-Filter select p.name, count(b)
from Publisher p
left join p.books b
on b.bookType = BookType.PAPERBACK
group by p.name
– TREAT: Downcast (inkl. Filterung)
select s from StorageLocation s
where treat(s.product as Book).bookType = BookType.HARDCOVER
– FUNCTION: Aufruf von DB-Funktionen
select c from Customer c
where function('hasGoodCredit', c.balance, c.creditLimit)
29 Java Persistence in Action dirk.weil@gedoplan.de
31. JPA 2.1 – What's coming?
• ConstructorResult für native Queries
Query query = entityManager.createNativeQuery(
"select name, price from product", "NameAndPriceResult");
List<NameAndPrice> result = query.getResultList();
public class NameAndPrice {
public NameAndPrice(String name, double price)
@Entity
@SqlResultSetMapping(name = "NameAndPriceResult",
classes = { @ConstructorResult(
targetClass = NameAndPrice.class,
columns = { @ColumnResult(name = "name"),
@ColumnResult(name = "price")
})
})
public abstract class Product {
31 Java Persistence in Action dirk.weil@gedoplan.de
32. JPA 2.1 – What's coming?
• Konverter
@Converter
public class YesNoConverter implements AttributeConverter<Boolean, String> {
public String convertToDatabaseColumn(Boolean fieldValue) {
if (fieldValue == null) return null;
return fieldValue ? "Y" : "N";
}
public Boolean convertToEntityAttribute(String columnValue) {
if (columnValue == null) return null;
return columnValue.equals("Y");
@Entity
public abstract class Product
{
@Convert(converter = YesNoConverter.class)
private boolean active;
32 Java Persistence in Action dirk.weil@gedoplan.de
33. JPA 2.1 – What's coming?
• CDI Injection in Entity Listener
public class CountryListener {
@Inject
private AuditService auditService;
@PreUpdate
public void preUpdate(Object entity) {
this.auditService.logUpdate(entity);
}
@Entity
@EntityListeners(CountryListener.class)
public class Country {
33 Java Persistence in Action dirk.weil@gedoplan.de
34. JPA 2.1 – What's coming?
• Unsynchronisierter Persistence Context
@PersistenceContext(
name = "default",
synchronization = SynchronizationType.UNSYNCHRONIZED)
private EntityManager entityManager;
– keine automatische TX-Bindung
– API zum Binden an TX:
EntityManager.joinTransaction()
EntityManager.isJoinedWithTransaction()
34 Java Persistence in Action dirk.weil@gedoplan.de
35. JPA 2.1 – What's coming?
• Dynamische Erzeugung von Named Queries
• DDL Handling
35 Java Persistence in Action dirk.weil@gedoplan.de
36. JPA 2.1 – (bisher nur) vorgeschlagen
• Fetch groups
• Immutable attributes, readonly entities
• UUID generator
• Multitenancy
• Dirty detection
• Mapping between JPQL and criteria queries.
36 Java Persistence in Action dirk.weil@gedoplan.de
37. JPA 2.1 – Reicht das?
• Ja
– für neue Anwendungen
– in 90%+ der Fälle
• Aber:
– Legacy Databases
– Performance
37 Java Persistence in Action dirk.weil@gedoplan.de
38. JPA 2.1 – Reicht das?
• Legacy Databases
EclipseLink Hibernate OpenJPA
Optimistic Locking ohne Version
weitere Generatoren
Inheritance ohne Diskriminator
Column
Polymorphe Assoziationen
Custom CRUD SQL
…
38 Java Persistence in Action dirk.weil@gedoplan.de
39. JPA 2.1 – Reicht das?
• Performance
EclipseLink Hibernate OpenJPA
R/O Entities
Index
Eager Load Tuning
Batch Fetching
Partitioning
Cascading Delete in DB
…
39 Java Persistence in Action dirk.weil@gedoplan.de
40. JPA 2.1 – Reicht das?
• Wunschliste ist nicht leer
– Vieles bereits proprietär vorhanden
• Portabilität ist hohes Gut
Standard weiter entwickeln!
40 Java Persistence in Action dirk.weil@gedoplan.de
41. Schön, dass Sie da waren!
Di, 20:30: Java EE Day Panel
Mi, 16:30: Gute Zeilen, schlechte Zeilen
Mi, 19:45: Java on Tracks
dirk.weil@gedoplan.de