jpa pitfalls und unknown features
Post on 27-May-2015
835 Views
Preview:
DESCRIPTION
TRANSCRIPT
Arne Limburg | open knowledge GmbH
@ArneLimburg @_openknowledge
Meine Person Arne Limburg Head of Development open knowledge GmbH
@ArneLimburg @_openknowledge
www.openknowledge.de
equals und hashCode
equals und hashCode • Object-Identity ≠ Datenbank-Identität • Equals und HashCode basieren auf Id • Keine Entitäten ohne Id in
HashSet / HashMap! – Vorher persistieren oder – andere Set- / Map-Implementierung
verwenden
Id-Generierung
Id-Generierung • Niemals GenerationType.AUTO
verwenden! • Nur GenerationType.TABLE ist
datenbank-unabhängig!
Subclassing
Subclassing • Vorsicht bei
– Table-per-Class – Joined
• Empfehlung Single-Table mit @SecondaryTable
• Unknown Feature Abfragen der konkreten Klasse in JPQL mit TYPE(...)
Lazy-Loading
New
Managed Detached
Removed
entityManager.persist entityManager.merge
entityManager.remove
entityManager.detach entityManager.close
entityManager.merge entityManager.find query.getResultList() query.getSingleResult()
Entity-Lebenszyklus
New
Managed
Removed
entityManager.persist entityManager.merge
entityManager.remove
entityManager.detach entityManager.close
entityManager.merge entityManager.find query.getResultList() query.getSingleResult()
Entity-Lebenszyklus
Detached
Achtung: Lazy-Initialization nicht im Zustand
„detached“
Lazy Loading • Explizites Fetchen
– via JPQL – via Criteria – Manuell – Ab JPA 2.1 Fetch-Graphs
• Unknown Features – JPA Metadaten – PersistenceUnitUtil
Lazy Loading • Explizites Fetching (wie gesehen) • Aufpassen mit N+1-SELECTs • Unknown Features
EntityManager.getReference PersistenceUnitUtil
Wann wird der EntityManager eigentlich geschlossen?
Container-Managed Variante 1 • Session Bean (Stateful oder Stateless)
– Transaktionsgrenze: Business-Methode (Transaction-Propagation)
– Beeinflussung durch @TransactionAttribute • Scope:
– Transactional – Mit Persistence-Context-Propagation
@Stateless public class UserRepositoryEjb { @PersistenceContext private EntityManager em; … }
@Stateless public class UserRepositoryEjb { @PersistenceContext private EntityManager em; … public void businessMethod() { // EntityManager available } }
Transaction-Scoped
@Stateless public class UserRepositoryEjb { @PersistenceContext private EntityManager em; … }
@Stateless public class UserRepositoryEjb { @PersistenceContext private EntityManager em; … public void businessMethod() { // EntityManager available } }
@Stateless public class UserRepositoryEjb { @PersistenceContext private EntityManager em; … @TransactionAttribute(NEVER) public void businessMethod() { // EntityManager not available } }
Transaction-Scoped
Java-EE-5-Architektur
Transaktions- grenze
Vorsicht mit Lazy- Initialization
Container-Managed Variante 2 • Stateful Session Bean • EXTENDED EntityManager
– Transaktionsgrenze à wie bei Variante 1
– Lesen ohne Transaktion à Lazy-Loading möglich
– Scope Session
@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 } }
Session-Scoped
@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
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
Producer für CDI @Stateless public class UserServiceEjb { @Produces @PersistenceContext private EntityManager em; … } public class UserDao { @Inject private EntityManager em; }
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)
JPA und CDI
CDI bietet viele Scopes und ausgefeiltes Lifecycle-Management!
Kann das nicht für den EntityManager
genutzt werden?
Application-Managed • Erzeugung via
entityManagerFactory.createEntityManager(…)
• Transaktionsbehandlung (Manuell) – JTA entityManager.joinTransaction() – RESOURCE_LOCAL entityManager.getTransaction().begin() entityManager.getTransaction().commit()
• Scope EXTENDED (Manuelle Verwaltung)
Application-Managed • Erzeugung via
entityManagerFactory.createEntityManager(…)
• Transaktionsbehandlung (Manuell) – JTA entityManager.joinTransaction() – RESOURCE_LOCAL entityManager.getTransaction().begin() entityManager.getTransaction().commit()
• Scope EXTENDED (Manuelle Verwaltung)
Nachteil: Keine PerstenceContext-Propagation!
Request-Scoped EntityManager @ApplicationScoped public class MyPersistenceUnit { @Produces @RequestScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } … }
Lifecycle-Management von CDI @ApplicationScoped public class MyPersistenceUnit { … public void closeEntityManager( @Disposes EntityManager entityManager) { entityManager.close(); } }
Architektur mit CDI EntityManager lifecycle
Lazy-Initialization möglich
Pitfall: transaction-type
Offen: Transaktionsgrenze
CDI Interceptoren @Transactional @Interceptor public class MyTransactionalInterceptor { @Inject private EntityManager em; … }
CDI Interceptoren @InterceptorBinding @Target({TYPE, METHOD, PARAMETER, FIELD}) @RETENTION(RUNTIME) public @interface Transactional { }
CDI Interceptoren @Transactional @Interceptor public class MyTransactionalInterceptor { @Inject private EntityManager em; … }
CDI Interceptoren … @AroundInvoke public Object startTransaction( InvocationContext context) throws … { em.getTransaction().begin(); try { return context.proceed(); } finally { em.getTransaction().commit(); } }
CDI Interceptoren @ApplicationScoped public class MyUserDao { @Inject private EntityManager em; @Transactional public void persist(User user) { em.persist(user); } }
Weitere Scopes? @ApplicationScoped public class MyPersistenceUnit { @Produces @RequestScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } … }
Conversation-Scope? @ApplicationScoped public class MyPersistenceUnit { @Produces @ConversationScoped public EntityManager createEntityManager( EntityManagerFactory factory) { return factory.createEntityManager(); } … }
Producer für CDI @Stateful @ConversationScoped public class UserServiceEjb { @Produces @RequestScoped @PersistenceContext(type = EXTENDED) private EntityManager em; … }
Producer für CDI @Stateful @ConversationScoped public class UserServiceEjb { @Produces @PersistenceContext(type = EXTENDED) private EntityManager em; … }
Funktioniert aktuell nur mit Hibernate!
Architektur mit CDI EntityManager lifecycle
Lazy-Initialization möglich
Proxy vs. Enhancement
Proxy vs. Enhancement • Aufpassen bei
– equals – Subclassing – Serialisierung – Lazy to-one-Beziehungen
Locking
Locking Programmatisches Locken • EntityManager
lock , find , refresh • Query
setLockMode
• @NamedQuery lockMode-Element
LockModeType • OPTIMISTIC (= READ) • OPTIMISTIC_FORCE_INCREMENT (= WRITE)
• PESSIMISTIC_READ • PESSIMISTIC_WRITE • PESSIMISTIC_FORCE_INCREMENT • NONE
Unknown Features • javax.persistence.lock.timeout • javax.persistence.lock.scope
PessimisticLockScope – NORMAL – EXTENDED
Vielen Dank für Ihre Zeit. Kontakt: open knowledge GmbH Bismarckstr. 13 26122 Oldenburg arne.limburg@openknowledge.de @ArneLimburg @_openknowledge
Q&A
top related