java persistence in action – einsatz von jpa 2.x in java-ee-anwendungen

Post on 19-Jun-2015

1.049 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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.

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