Real life persistence

73
Arne Limburg | open knowledge GmbH Real Life Persistence

description

Mit JPA 2.1 wurde in Java EE 7 ein weiterer Schritt in Richtung Provider-Unabhängigkeit gegangen. Auch wenn damit weitere Möglichkeiten des Einsatzes mit JPA geschaffen wurden, gibt es in der Praxis weiterhin viele Dinge zu beachten.In der Session werden neben klassischen Architekturansetzen zum Einsatz von JPA auch weitergehende Herausforderungen diskutiert. Wie kann JPA im Zusammenhang mit den neuen JSRs für Batch-Verarbeitung und den Concurrency Utilities beleuchtet, die erweitere Möglichkeiten im Bereich Asynchronität bieten?

Transcript of Real life persistence

Page 1: Real life persistence

Arne Limburg | open knowledge GmbH

Real Life Persistence

Page 2: Real life persistence

Arne LimburgHead of Architecture and Technologyopen knowledge GmbH

@ArneLimburg@_openknowledge

www.openknowledge.de

Meine Person

Page 3: Real life persistence

Beispiel

Page 4: Real life persistence

N + 1 SELECTS

Page 5: Real life persistence

Lazy Loading

Page 6: Real life persistence

Lazy Loading

Problemstellung:

Wann werden die Daten aus der Datenbank geladen?

Beispiel:

Customer customer = entityManager.find(Customer.class, id);Address address = customer.getAddress();String street = address.getStreet();

//Wann wird die Adresse aus der Datenbank geladen?

Page 7: Real life persistence

Lazy Loading

Möglichkeit 1: Wenn ein User geladen wird, werden alle angehängten Objekte mitgeladen!

Problem: Wenn alle Objekte zusammenhängen, wird bei jedem Select der gesamte Datenbank-Inhalt geladen!

Page 8: Real life persistence

Lazy Loading

Möglichkeit 2: Anhängende Objekte werden nie mitgeladen!

Problem:

Customer customer = entityManager.find(Customer.class, id);Address address = customer.getAddress();String street = address.getStreet();//führt zu LazyInitializationException

Page 9: Real life persistence

Lazy Loading

Möglichkeit 3: Anhängende Objekte werden nachgeladen, wenn sie gebraucht werden!Vorgehen von JPA bei geöffnetem

EntityManagerBei geschlossenem EntityManager führt Zugriff

auf nicht geladene Entitäten zu einem Fehler

Page 10: Real life persistence

Lazy Loading

Beeinflussungsmöglichkeiten des Nachladens

>Mapping

>Query

>Manuell (Test über PersistenceUnitUtil)

>Entity Graph Neu ab JPA 2.1

Page 11: Real life persistence

Lazy Loading

Nachladen beeinflussen über Mapping

>fetch-Attribut an

>@ManyToOne (default EAGER)

>@OneToOne (default EAGER)

>@OneToMany (default LAZY)

>@ManyToMany (default LAZY)

Page 12: Real life persistence

Lazy Loading

Nachladen beeinflussen über Query

>Angabe von join fetch in JPQL

>Angabe von root.fetch(…)in Criteria

Page 13: Real life persistence

Lazy Loading

Manuell

>Zugriff auf Objekt führt zu Nachladen

>Überprüfen des Ladezustandes mit PersistenceUnitUtil>Über EntityManagerFactory

>Zusätzlich Möglichkeit, die Id zu erhalten

Neu seit JPA 2

Page 14: Real life persistence

Entity Graph

>Spezifikation des Fetch-Verhaltens

>Find-Operationen (via Map)

>Queries (via setHint)

>Angabe über

>javax.persistence.fetchgraph Alle nicht enthaltenen Attribute lazy

>javax.persistence.loadgraph Alle nicht enthaltenen Attribute default

Neu seit JPA 2.1

Page 15: Real life persistence

@NamedEntityGraph( name = "User.fetchRoles", attributeNodes = { @NamedAttributeNode("name"), @NamedAttributeNode(value = "roles", subgraph = "role") }, subgraphs = { @NamedSubgraph(name = "role", attributeNodes = …)}) public class User {

Entity Graph

Page 16: Real life persistence

EntityGraph<User> userGraph = entityManager .createEntityGraph(User.class);userGraph.addAttributeNode(User_.name);Subgraph<Role> role = userGraph.addSubgraph(User_.roles);role.addAttributeNode(…);

Entity Graph

Page 17: Real life persistence

Proxy vs. Enhancement

Page 18: Real life persistence

Proxy vs. Enhancement

Aufpassen bei

>equals>Subclassing

>Serialisierung

>Lazy to-one-Beziehungen

Page 19: Real life persistence

New

Managed Detached

Removed

entityManager.persistentityManager.remove

entityManager.detachentityManager.clearentityManager.close

entityManager.mergeentityManager.findquery.getResultList()query.getSingleResult()

Entity-Lebenszyklus

entityManager.merge

Page 20: Real life persistence

New

Managed

Removed

entityManager.persistentityManager.merge

entityManager.remove

entityManager.detachentityManager.close

entityManager.mergeentityManager.findquery.getResultList()query.getSingleResult()

Entity-Lebenszyklus

Detached

Achtung:

Lazy-Initialization nicht im Zustand „detached“

Page 21: Real life persistence

Wann wird der EntityManagereigentlich geschlossen?

Page 22: Real life persistence

Fragestellungen

>EntityManager

>Container- vs. Application-Managed

>Transactional vs. Extended

>Transaction

>JTA vs. Resource Local

>Synchronized vs. Unsynchronized

>Datasource

>JNDI vs. local

>JTA vs. Non-JTA

Page 23: Real life persistence

Application-Managed

>Erzeugung via emf.createEntityManager(…)

>Transaktionsbehandlung (Manuell)

>JTA em.joinTransaction()>RESOURCE_LOCAL em.getTransaction().begin() em.getTransaction().commit()

>Scope EXTENDED (Manuelle Verwaltung)

Page 24: Real life persistence

Application-Managed

>Erzeugung via emf.createEntityManager(…)

>Transaktionsbehandlung (Manuell)

>JTA em.joinTransaction()>RESOURCE_LOCAL em.getTransaction().begin() em.getTransaction().commit()

>Scope EXTENDED (Manuelle Verwaltung)

Nachteil:

Keine PerstenceContext-Propagation!

Page 25: Real life persistence

Container-Managed

Variante 1

>Session Bean (Stateful oder Stateless)

>Transaktionsgrenze: Business-Methode (Transaction-Propagation)

>Beeinflussung durch @TransactionAttribute

>Scope:

>Transactional

>Mit Persistence-Context-Propagation

Page 26: Real life persistence

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; …

}

Transaction-Scoped

Page 27: Real life persistence

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; …

}

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; …

public void businessMethod() { // EntityManager available } }

Transaction-Scoped

Page 28: Real life persistence

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; …

}

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; …

public void businessMethod() { // EntityManager available } }

@Stateless public class UserDaoEjb { @PersistenceContext private EntityManager em; … @TransactionAttribute(NEVER) public void businessMethod() { // EntityManager not available } }

Transaction-Scoped

Page 29: Real life persistence

Transaktions-grenze

Vorsicht mit Lazy-Initialization

Java-EE-5 Architektur

Page 30: Real life persistence

Container-Managed

Variante 2

>Stateful Session Bean

>EXTENDED EntityManager

>Transaktionsgrenze

wie bei Variante 1

>Lesen ohne Transaktion

Lazy-Loading möglich

>Scope Session

Page 31: Real life persistence

@Stateful public class UserDaoEjb { @PersistenceContext(type = EXTENDED) private EntityManager em; …

}

@Stateful public class UserDaoEjb { @PersistenceContext(type = EXTENDED) private EntityManager em; …

public void businessMethod() { // EntityManager available } }

@Stateful public class UserDaoEjb { @PersistenceContext(type = EXTENDED) private EntityManager em; … @TransactionAttribute(NEVER) public void businessMethod() { // EntityManager available } }

Session-Scoped

Page 32: Real life persistence

@Stateful public class UserDaoEjb { @PersistenceContext( synchronization = UNSYNCHRONIZED) private EntityManager em; …

}

@Stateful public class UserDaoEjb { @PersistenceContext( synchronization = UNSYNCHRONIZED) private EntityManager em; … public void businessMethod() {

// no flush after invocation } }

@Stateful public class UserDaoEjb { @PersistenceContext( synchronization = UNSYNCHRONIZED) private EntityManager em; … public void businessMethod() { em.joinTransaction(); // flush‘n‘commit after invocation } }

Neu seit JPA 2.1

Unsynchronized

Page 33: Real life persistence

Container-Managed

Zusatz-Feature Java EE 6

>Service-Schicht als EJBs

>DAO-Schicht als CDI Beans

>EJB stellt EntityManager zur Verfügung @Produces

>Injection des EntityManagers in CDI-Beans @Inject

Page 34: Real life persistence

Producer für CDI

@Stateless public class UserServiceEjb { @Produces @PersistenceContext private EntityManager em; … }

public class UserDao { @Inject private EntityManager em; }

Page 35: Real life persistence

Fazit EJB-Integration

>Injection in Session Beans (stateful und stateless)

>Transaktionsgrenze

>Methodenaufruf der Session Bean (inklusive Transaction-Propagation)

>Scopes

>Transaction (alle Session Beans)

>Session (Stateful Session Beans)

Page 36: Real life persistence

public class MyEntityListener { @Inject @Current private User user;

@PrePersist public void setCreator(MyEntity e) { e.setCreator(user); } }

Neu seit JPA 2.1

CDI-Integration

Page 37: Real life persistence

public class MyEntityListener { @Inject @Current private User user;

@PrePersist public void setCreator(MyEntity e) { e.setCreator(user); } }

Achtung:

Verhalten bei Zugriff auf andere Entitäten oder Verändern von Beziehungen ist nicht

standardisiert.

Neu seit JPA 2.1

CDI-Integration

Page 38: Real life persistence

CDI bietet viele Scopes und ausgefeiltes

Lifecycle-Management!

Kann das nicht für den EntityManager genutzt werden?

CDI-Integration außerhalb des Standards

Page 39: Real life persistence

@ApplicationScopedpublic class MyPersistenceUnit { @Produces @RequestScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } …}

Request-Scoped EntityManager

Page 40: Real life persistence

@ApplicationScopedpublic class MyPersistenceUnit { …

public void closeEntityManager( @Disposes EntityManager entityManager) {

entityManager.close(); }}

Lifecycle-Management von CDI

Page 41: Real life persistence

EntityManagerlifecycle

Lazy-Initializationmöglich

Architektur mit CDI

Page 42: Real life persistence

EntityManagerlifecycle

Lazy-Initializationmöglich

Offen:

Transaktionsgrenze

Architektur mit CDI

Page 43: Real life persistence

@Transactional @Interceptorpublic class MyTransactionalInterceptor { @Inject private EntityManager em;

…}

CDI-Interceptor

Page 44: Real life persistence

… @AroundInvoke public Object startTransaction( InvocationContext context) throws … { em.getTransaction().begin(); try { return context.proceed(); } finally { em.getTransaction().commit(); } }

CDI-Interceptor

Page 45: Real life persistence

@ApplicationScopedpublic class MyUserDao { @Inject private EntityManager em;

@Transactional public void persist(User user) { em.persist(user); }}

CDI-Interceptor

Page 46: Real life persistence

@ApplicationScopedpublic class MyPersistenceUnit { @Produces @RequestScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } …}

Weitere Scopes

Page 47: Real life persistence

@ApplicationScopedpublic class MyPersistenceUnit { @Produces @ConversationScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } …}

Conversation-Scope?

Page 48: Real life persistence

@Stateful @ConversationScoped public class UserServiceEjb { @Produces @RequestScoped @PersistenceContext(type = EXTENDED) private EntityManager em; … }

Producer für CDI

Page 49: Real life persistence

@Stateful @ConversationScoped public class UserServiceEjb { @Produces @RequestScoped @PersistenceContext(type = EXTENDED) private EntityManager em; … }

Passivation nur in einigen Containern

Producer für CDI

Page 50: Real life persistence

Asynchronität

Page 51: Real life persistence

By default, session bean invocationsthrough the Remote, Local, and no-

interface views are synchronous.Clients can achieve asynchronous

invocation behavior by invoking session bean methods that

have been designed to support asynchrony.

@Asynchronous

Zitat: EJB Spezifikation, v 3.1

Page 52: Real life persistence

@Asynchronous

EJB 3.1 Asynchronität

>Leichtgewichtig (analog zu Java SE) java.util.concurrent.Future

>Markierung via @Asynchronous>Methodensignatur

>Parameter beliebig

>Rückgabewert Future oder void

Page 53: Real life persistence

@Asynchronous

@Asynchronouspublic void broadcast(List<Email> receipients, String message) { …}

@Asynchronouspublic Future<Result> compute(…) { … return new AsynchResult<Result>(…);}

Page 54: Real life persistence

java.util.concurrent.Future

public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}

Page 55: Real life persistence

@Asynchronous Pro & Contra

>Einfacher Mechanismus >Separate Transaktion >Separater EntityManager

>Potentiell „gefährlich“

>Anzahl gestarteter Threads nicht limitierbar

>Thread Leaks (Threads die nicht enden bis zum

Restart des Containers)

>EntityManager ist Single-Threaded> 7

6

Page 56: Real life persistence

Locking

Page 57: Real life persistence

Locking

Optimistic

>@VersionProgrammatisches Locken

>EntityManager - lock , find , refresh>Query - setLockMode>@NamedQuery - lockMode-Element

Page 58: Real life persistence

Lock-Modes

>READ (deprecated)

>WRITE (deprecated)

>OPTIMISTIC

>OPTIMISTIC_FORCE_INCREMENT

>PESSIMISTIC_READ

>PESSIMISTIC_WRITE

>PESSIMISTIC_FORCE_INCREMENT

>NONE

Page 59: Real life persistence

Caching

Page 60: Real life persistence

Caching

Der First-Level-Cache

>EntityManager-Cache

>Caching von Entitäten

Page 61: Real life persistence

Caching

Der Second-Level-Cache

>EntityManagerFactory-Cache

>Implementierung provider-spezifisch

>Zugriff über Ids

Page 62: Real life persistence

Konfiguration

persistence.xml<persistence ...> <persistence-unit name="Weblog" ...>

<class>...</class>

<shared-cache-mode>ALL</shared-cache-mode>

<!– alternativ --> <properties> <property name="javax.persistence.sharedCache.mode" value="ALL" /> </properties> </persistence-unit></persistence>

Page 63: Real life persistence

SharedCacheMode

>ALL>NONE>ENABLE_SELECTIVE>DISABLE_SELECTIVE>UNSPECIFIED

Page 64: Real life persistence

@Entity @Cachable // = @Cachable(true) public class User { … }

Caching

Page 65: Real life persistence

@Entity @Cachable(false) public class User { … }

Caching

Page 66: Real life persistence

@Entity // Keine Cache-Annotation public class User { … }

Caching

Page 67: Real life persistence

Caching

EntityManagerFactory.getCache()Abfragen und Löschen des Cache-Inhalts

Beeinflussen des Cache-Verhaltens bei einzelnen Operationen:

>javax.persistence.cache.retrieveMode>javax.persistence.cache.storeMode

Page 68: Real life persistence

Caching

>CacheRetrieveMode

>USE (default)

>BYPASS>CacheStoreMode

>USE (default)

>BYPASS>REFRESH

Page 69: Real life persistence

JPA vs. NoSQL

Page 70: Real life persistence

JPA vs. NoSQL

JPA

>Halten der Daten im Heap

>Verwaltung von Objekten mit Klassenstruktur (Java-Objekte)

NoSQL

>Verwalten großer Datenmengen

>Verwalten von unstrukturierten Objekten (Dokumente, JSON-Objekte)

Page 71: Real life persistence

JPA und NoSQL

Page 72: Real life persistence

JPA und NoSQL

>Abfragen beider Datastores

>Relational für strukturierte Daten

>NoSQL für unstrukturierte Daten

>Zusammenführen beider Ergebnisse im Speicher

>Übertragen der NoSQL-Daten in Map

Page 73: Real life persistence

Vielen Dank für Ihre Zeit.

Kontakt:

open knowledge GmbHBismarckstr. 1326122 Oldenburg

[email protected]

@ArneLimburg @_openknowledge

Questions & Answers