java persistence in action – einsatz von jpa 2.x in java-ee-anwendungen
Post on 19-Jun-2015
1.049 Views
Preview:
DESCRIPTION
TRANSCRIPT
Java Persistence in ActionEinsatz von JPA 2.x in Java-EE-Anwendungen
Dirk Weil | GEDOPLAN
dirk.weil@gedoplan.de
Dirk Weil• GEDOPLAN GmbH, Bielefeld• Java EE seit 1998• Konzeption und
Realisierung• Vorträge• Seminare• Veröffentlichungen
Java Persistence in Action2
dirk.weil@gedoplan.de
ZEILEN
Java Persistence in Action3
dirk.weil@gedoplan.de
Java Persistence in EE-Anwendungen• Basics:
– META-INF/persistence.xml referenziert Datasource
– EntityManager-Bereitstellung per Injektion
<persistence …>
<persistence-unit name="beantrial">
<jta-data-source>jdbc/beantrial</jta-data-source>
…
@PersistenceContext(unitName = "beantrial")
EntityManager entityManager;
Java Persistence in Action4
dirk.weil@gedoplan.de
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 FirmaRepository {
@Inject
EntityManager entityManager;
public class ProjektRepository {
@Inject
EntityManager entityManager;
Java Persistence in Action5
dirk.weil@gedoplan.de
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?
Java Persistence in Action6
dirk.weil@gedoplan.de
Entity Manager Lifecycle
@Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
<h:dataTable value="#{personModel.personen}" var="person">
…
<h:… value="#{person.hobbies}" />
…
@Entity
public class Person {
@ElementCollection(fetch = FetchType.LAZY)
private List<String> hobbies;
LazyLoadException
?
Java Persistence in Action7
dirk.weil@gedoplan.de
Entity Manager Lifecycle• EM-Optionen:
– Transaction-scoped– (Extended)*– Application-managed
• Patterns– Eager Loading– Open Entity Manager in View– Conversational Entity Manager
*nur Stateful EJBs – nicht weiter betrachtet
Java Persistence in Action8
verschiedene Kombinationen möglich
dirk.weil@gedoplan.de
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;
Java Persistence in Action9
dirk.weil@gedoplan.de
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)
Java Persistence in Action10
dirk.weil@gedoplan.de
Transaction-scoped Entity Manager
@Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
<h:dataTable value="#{personModel.personen}" …>
…
<h:… value="#{person.hobbies}" />
@Transactional
public class PersonRepository {
public List<Person> findAll() { … }
DB
View
Model
ServiceTX
deta
ched
man
aged
Java Persistence in Action11
dirk.weil@gedoplan.de
Transaction-scoped Entity Manager• Eager Loading nötig
– deklarativ
– oder durch explizitenZugriff
@ElementCollection(fetch = FetchType.EAGER)
private List<String> hobbies;
public void loadLazyAttributes() {
this.hobbies.size();
Java Persistence in Action12
dirk.weil@gedoplan.de
Transaction-scoped Entity Manager• Code Browsing:
Personenverwaltung mit detached Entities
Java Persistence in Action13
(Download: www.gedoplan.de� Blog
dirk.weil@gedoplan.de
Transaction-scoped Entity Manager• Alternative: Transaction per Request
@Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
<h:dataTable value="#{personModel.personen}" …>
…
<h:… value="#{person.hobbies}" />
View
Model
TX
…
Java Persistence in Action14
dirk.weil@gedoplan.de
Transaction-scoped Entity Manager• Transaction per Request
– mittels Servlet Filter– mittels JSF Phase Listener
– Seam Transaction / Seam FacesAchtung: Per Default aktiv !(Abschalten: Siehe www.gedoplan.de� Blog)
Java Persistence in Action15
dirk.weil@gedoplan.de
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
Java Persistence in Action16
dirk.weil@gedoplan.de
Application-managed Entity Manager• Nutzung von EntityManagerFactory
• Lifecycle wird von Anwendung bestimmtpublic 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();
}
Java Persistence in Action17
dirk.weil@gedoplan.de
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();
}
Java Persistence in Action18
dirk.weil@gedoplan.de
Request-scoped Entity Manager• Request
Scope= Open Entity Manager in View
@Produces
@RequestScoped
public EntityManager createEntityManager() {
Ent
ityM
anag
er
@Model
public class PersonModel {
public List<Person> getPersonen() {
… personRepository.findAll() …
<h:dataTable value="#{personModel.personen}" …>
…
<h:… value="#{person.hobbies}" />
@Transactional
public class PersonRepository {
public void saveAll() { … }
DB
View
Model
Service
TX
Java Persistence in Action19
dirk.weil@gedoplan.de
EM
EM
Conversation-scoped Entity Manager• Conversational
Entity Manager
@Produces
@ConversationScoped
public EntityManager createEntityManager() {
Request 2Conversation.begin()
Request 1
Request 3
Request 4Conversation.end()
Java Persistence in Action20
dirk.weil@gedoplan.de
Conversation-scoped Entity Manager• ABER:
– Conversation Scope ist passivating– Objekte in ihm müssen serialisierbar sein– EntityManager nicht notwendigerweiseSerializable
• Abhilfe: Serializable-Wrapper
Java Persistence in Action21
dirk.weil@gedoplan.de
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;
}
Java Persistence in Action22
dirk.weil@gedoplan.de
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);
}
}
Java Persistence in Action23
dirk.weil@gedoplan.de
Conversation-scoped Entity Manager• Serializable-Wrapper:
– Prinzip Hoffnung:Wahrscheinlich keine Passivierung;wenn doch, ordentliche Fehlermeldung.
– Ungeeignet für Replikation
Java Persistence in Action24
dirk.weil@gedoplan.de
Conversation-scoped Entity Manager• Code Browsing:
Personenverwaltung mit attached Entities
Java Persistence in Action25
(Download: www.gedoplan.de� Blog
dirk.weil@gedoplan.de
SQL-Zugriffe im Beispiel
Aktion TX-scoped EM Conv-scoped EM
Anzeige aller PersonenSELECT ID, ... FROM PERSON dito
Auswahl einer Person zum EditierenSELECT ID, ... FROM PERSON WHERE (ID = ?)
SELECT TEL, ... FROM PERSON_TELWHERE (PERSON_TEL.Person_ID = ?)
dito
SELECT HOBBY, ... FROM PERSON_HOBBYWHERE (PERSON_HOBBY.Person_ID = ?)
Java Persistence in Action26
dirk.weil@gedoplan.de
SQL-Zugriffe im Beispiel
Aktion TX-scoped EM Conv-scoped EM
Ändern des Vornamens und Speichern der PersonSELECT ID, ... FROM PERSONWHERE (ID = ?)
SELECT TEL, ... FROM PERSON_TELWHERE (PERSON_TEL.Person_ID = ?)
SELECT HOBBY, ... FROM PERSON_HOBBYWHERE (PERSON_HOBBY.Person_ID = ?)
UPDATE PERSON SET VORNAME = ?WHERE (ID = ?)
dito
Java Persistence in Action27
dirk.weil@gedoplan.de
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
Java Persistence in Action28
dirk.weil@gedoplan.de
JPA 2.1 – What's coming?• Query-Erweiterungen
– ON: Join-Filter
– TREAT: Downcast (inkl. Filterung)
– FUNCTION: Aufruf von DB-Funktionen
select p.name, count(b)
from Publisher p
left join p.books b
on b.bookType = BookType.PAPERBACK
group by p.name
select s from StorageLocation s
where treat(s.product as Book).bookType = BookType.HARDCOVER
select c from Customer c
where function('hasGoodCredit', c.balance, c.creditLimit)
Java Persistence in Action29
dirk.weil@gedoplan.de
JPA 2.1 – What's coming?• Bulk Update/Delete für Criteria Query
• Stored Procedure Queries
CriteriaUpdate<Product> criteriaUpdate
= criteriaBuilder.createCriteriaUpdate(Product.class);
Root<Product> p = criteriaUpdate.from(Product.class);
Path<Number> price = p.get(Product_.price);
criteriaUpdate.set(price, criteriaBuilder.prod(price, 1.03));
entityManager.createQuery(criteriaUpdate).executeUpdate();
StoredProcedureQuery query
= entityManager.createStoredProcedureQuery("findMissingProducts");
Java Persistence in Action30
dirk.weil@gedoplan.de
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();
@Entity
@SqlResultSetMapping(name = "NameAndPriceResult",
classes = { @ConstructorResult(
targetClass = NameAndPrice.class,
columns = { @ColumnResult(name = "name"),
@ColumnResult(name = "price")
})
})
public abstract class Product {
public class NameAndPrice {
public NameAndPrice(String name, double price)
Java Persistence in Action31
dirk.weil@gedoplan.de
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;
Java Persistence in Action32
dirk.weil@gedoplan.de
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 {
Java Persistence in Action33
dirk.weil@gedoplan.de
JPA 2.1 – What's coming?• Unsynchronisierter Persistence Context
– keine automatische TX-Bindung– API zum Binden an TX:EntityManager.joinTransaction()EntityManager.isJoinedWithTransaction()
@PersistenceContext(
name = "default",
synchronization = SynchronizationType.UNSYNCHRONIZED)
private EntityManager entityManager;
Java Persistence in Action34
dirk.weil@gedoplan.de
JPA 2.1 – What's coming?• Dynamische Erzeugung von Named Queries• DDL Handling
Java Persistence in Action35
dirk.weil@gedoplan.de
JPA 2.1 – (bisher nur) vorgeschlagen• Fetch groups• Immutable attributes, readonly entities• UUID generator• Multitenancy• Dirty detection• Mapping between JPQL and criteria queries.
Java Persistence in Action36
dirk.weil@gedoplan.de
JPA 2.1 – Reicht das?• Ja
– für neue Anwendungen– in 90%+ der Fälle
• Aber:– Legacy Databases– Performance
Java Persistence in Action37
dirk.weil@gedoplan.de
JPA 2.1 – Reicht das?• Legacy Databases
EclipseLink Hibernate OpenJPA
Optimistic Locking ohne Version � �
weitere Generatoren � � �
Inheritance ohne DiskriminatorColumn
� � �
Polymorphe Assoziationen � �
Custom CRUD SQL � �
…
Java Persistence in Action38
dirk.weil@gedoplan.de
JPA 2.1 – Reicht das?• Performance
EclipseLink Hibernate OpenJPA
R/O Entities � �
Index � � �
Eager Load Tuning � � �
Batch Fetching � �
Partitioning � �
Cascading Delete in DB � �
…
Java Persistence in Action39
dirk.weil@gedoplan.de
JPA 2.1 – Reicht das?• Wunschliste ist nicht leer
– Vieles bereits proprietär vorhanden
• Portabilität ist hohes Gut� Standard weiter entwickeln!
Java Persistence in Action40
Schön, dass Sie da waren!
Di, 20:30: Java EE Day Panel
Mi, 16:30: Gute Zeilen, schlechte ZeilenMi, 19:45: Java on Tracks
dirk.weil@gedoplan.de
top related