Search |
||
Persistence Context propagationPosted by ss141213 on October 27, 2006 at 11:01 AM PDT
What is persistence context propagation? Rules governing PC propagation 2. A PC is propagated along with the JTA transaction. 3. PC propagation is applicable only to local environments(i.e. one JVM). PC is not propagated across remote tiers even if the remote component is collocated in the same address space as the client. 4. A PC is propagated when the called component uses EM that belongs to the same Entity Manager Factory as the caller. 5. It is an application error to attempt to propagate a PC to a SFSB that is already associated with a different PC. In such a case, EJB container throws EJBException to the caller. Let's apply the rules (rule shown in ()) and see some cases where PC propagation takes place: 1. (rule #1) Since a container managed EM can only be obatined via @PersistenceContext or persistence-context-ref, PC propagation does not take place for EMs obtained using EntityManagerFactory.createEntityManager(). 2. (rule #2) A PC won't be propagated (e.g.) when an EJB with bean managed transaction or an EJB method with transaction attribute REQUIRES_NEW, NOT_SUPPORTED or NEVER is called because transactions are not propagated to such methods(see Chapter #13 of EJB 3.0 Core specification). More over, unless the caller is associated with a transaction, PC propagation will not happen. I don't know the behavior when a request is dispatched from one web component to another using using RequstDispatcher object. There are two questions that determine the answer, viz: a) is that ever considered a local call? b) does web container propagates the JTA transaction along with the request? If you know the answer, let me know. Else, I will try to find out myself. 3. (rule #3) Don't expect PC to be propagated when you call a remote EJB even when the remote EJB happens to be running in the same JVM or part of the same application. 4. (rule #4) All the components that want to share the PC must use the same persistence unit. Container internally creates an EntityManagerFactory corresponding to a persistence unit and uses it to create EMs. Persistence units defined in separate persistence.xml files or persistence units defined separately in one persistence.xml file are considered different no matter how idenically they are set up. So, if components from two different modules in an EAR file (e.g. a Servlet calling an EJB) want to share PC, then the persistence unit must be packaged as an EAR scoped persistence unit (e.g. in a jar file in lib folder of the EAR). 5. (rule #5) If a component is associated with a PC then it can't call a local SFSB with a different extended PC to which current transaction context will be propagated. GlassFish reports this very nice message when I tried doing this in a test case: javax.ejb.EJBException: There is an active transactional persistence context for the same EntityManagerFactory as the current stateful session bean's extended persistence context. (rule #5) These rules are not complete. Please refer to the JPA spec for more details. Sample Application 1. ReportServlet.java
EntityManager em = (EntityManager) new InitialContext().lookup(
"java:comp/env/persistence/EM1");
The above look up returns a valid EM because the Servlet has declared a dependency on a PC for the persistence unit named pu1 and has given this dependency a name persistence/EM1 using the following code:
@PersistenceContext(name="persistence/EM1", unitName="pu1")
public class ReportServlet extends HttpServlet {
ReportServlet begins a transaction using the injected UserTransaction object, obtains a managed entity instance by invoking lookup method of injected UserCredentialManager session bean, accesses the lazily fetched field of the entity and then commits the transaction in the code below:
utx.begin();
UserCredential user = ucm.lookupUser(name);
for(LoginAttempt attempt : user.getLoginAttempts()) {...}
utx.commit();
2. UserCredentialManagerBean.java: 3. Persistence Unit: You may have noticed that ReportServlet does not use the EM in any meaningful way. So, it can be totally removed from ReportServlet and yet ReportServlet will be able to use the entity in the same PC as that of the EJB. Let's see what would have happened if ReportServlet does not start the transaction before calling lookup method. Lookup method starts a new transaction and EJB container creates a new PC when the injected EM is used. This PC gets closed automatically when the transaction is ended at the end of that method, thus the returned entity becomes detached. Since fetch type for loginAttempts is LAZY (by default it is lazy for collection valued fields) and the field has not been accessed by lookup method, accessing it in the Servlet is asking for trouble (see section #3.2.4 of the JPA spec). GlassFish persistence provider is generous enough to allow such an access, but when I tested using OpenJPA, it threw a NullPointerException. Conclusion Resources »
Related Topics >>
J2EE Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|