-
1. Re: Synchronization of extended persistence contexts
smarlow Aug 24, 2011 1:32 PM (in response to gonne)1 of 1 people found this helpfulDuring the
TestDao.saveUser() call to em.persist(user), the extended persistence context (really its Hibernate session which is an internal detail), is used for the persist. When the TestDao.saveUser method returns, its TX is completed and all changes in the extended persistence context at that point are saved. This is by design, as the JPA specification
If you want isolation/separation between the TestBean persistence unit and the TestDao persistence unit, change them to use separate PU definitions. If the entire application is going to use the same persistence unit, then this interaction between extended persistence contexts and transactional persistence context is expected (the XPC on the invocation call stack, will be reused).
If you do separate the XPC into using a separate persistence unit, eventually, you need to invoke a transactional bean method, so that the xpc can be flushed to the database.
-
2. Re: Synchronization of extended persistence contexts
gonne Aug 25, 2011 7:35 AM (in response to smarlow)Hi Scott,
many thanks for your fast reply.
I tried to comprehend it by reading the JPA specification (7.6.3 PC Propagation, 7.6.3.1 Requirements for PC propagation), but I am not sure which case applies here.
{quote}
If a component is called and there is no JTA transaction or the JTA transaction is not propagated, the persistence context is not propagated.
• If an entity manager is then invoked from within the component:
• (a) Invocation of an entity manager defined with PersistenceContext-Type.TRANSACTION will result in use of a new persistence context
(as described in section 7.6.1).
• (b) Invocation of an entity manager defined with PersistenceContext-Type.EXTENDED will result in the use of the existing
extended persistence context bound to that component.
• (c) If the entity manager is invoked within a JTA transaction, the persistence context willbe bound to the JTA transaction.
If a component is called and the JTA transaction is propagated into that component:
• (d) If the component is a stateful session bean to which an extended persistence context has been bound and there is a different
persistence context bound to the JTA transaction, an EJBException is thrown by the container.
• (e) Otherwise, if there is a persistence context bound to the JTA transaction, that persistence context is propagated and used.
{quote}
I would say that my component TestDao is called and there is a JTA transaction, so PC is propagated (??).
In TestDao an entity manager is invoked within a JTA transaction (case c), so the PC will be bound to the JTA transaction and this results in the synchronization of the queued operations in the XPC after the commit of the JTA transaction.
Is that right?
Kind regards,
Gonne
-
3. Re: Synchronization of extended persistence contexts
smarlow Aug 25, 2011 1:13 PM (in response to gonne)1 of 1 people found this helpfulCurrently (and this goes back to earlier versions of JBoss AS (e.g. see https://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/epcpropagation/unit/EPCPropagationTestCase.java NoTxEPCStatefulBean testing), we are propagating the XPC into the SLSB invocation (which is why the synchronization of the queued operations occurs).
The JPA 2.0 specification specifically spells out, that this is correct for a SFSB (XPC) invoking a SFSB(PC). The specification doesn't directly say what should happen for a SFSB(XPC) invoking a SLSB(PC). I think the current JBoss way is useful but compatibility is more important.
I'll try to get further clarification on this.
-
4. Re: Synchronization of extended persistence contexts
smarlow Aug 26, 2011 11:28 AM (in response to smarlow)AS7-1663 is for changing the propagation logic in AS 7.0.2 to not propagate the XPC without it coming from an active JTA TX.
-
5. Re: Synchronization of extended persistence contexts
smarlow Aug 26, 2011 1:29 PM (in response to smarlow)After AS7-1663 is fixed, saveUser() should only commit the DAO operations to the database (the other change will remain in the XPC).
-
6. Re: Synchronization of extended persistence contexts
smarlow Aug 26, 2011 4:37 PM (in response to smarlow)AS7-1663 is resolved, please test with the nightly AS7 build (http://community.jboss.org/thread/167590) tomorrow. Write back here with your results.
-
7. Re: Synchronization of extended persistence contexts
gonne Aug 29, 2011 3:47 AM (in response to smarlow)Hi Scott,
I am glad about this change. I have tested my case with the nightly build yesterday and now it works as expected by me. Many thanks to you.
Kind regards,
Gonne
-
8. Re: Synchronization of extended persistence contexts
gonne Aug 29, 2011 12:19 PM (in response to gonne)Hi Scott,
I have created some further test cases which have changed their behaviour since your latest changes.
{code}
@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class TestSFSB {
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
@EJB
private TestDaoSLSB dao;
public User getUserNoTx(String name) {
// no tx, calling SLSB with new PC
User user = dao.findUserByName(name);
System.out.println("TestSFSB.getUserNoTx() user is " + (em.contains(user) ? "" : " NOT ") + " managed.");
return user;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public User getUserTx(String name) {
User user;
// SFSB with XPC and TX is calling SLSB with TX
user = dao.findUserByName(name);
try {
System.out.println("TestSFSB.getUserTx() user is " + (em.contains(user) ? "" : " NOT ") + " managed.");
}
catch(EJBException e) {
System.out.println("TestSFSB.getUserTx() ERROR breaking JPA spec 2.0 section 7.6.3.1");
}
return user;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public User getUserTxXpcPropagated(String name) {
User user;
user = em.createQuery("select u from User u where name = :name", User.class).setParameter("name", name).getSingleResult();
System.out.println("TestSFSB.getUserTxXpcPropagated() A user(" + user + ") is " + (em.contains(user) ? "" : " NOT ") + " managed.");
// SFSB with XPC and TX is calling SLSB with TX
user = dao.findUserByName(name);
System.out.println("TestSFSB.getUserTxXpcPropagated() B user(" + user + ") is " + (em.contains(user) ? "" : " NOT ") + " managed.");
return user;
}
}
@Stateless
public class TestDaoSLSB {
@PersistenceContext
private EntityManager em;
public User findUserByName(String name) {
return em.createQuery("select u from User u where u.name = :name", User.class)
.setParameter("name", name)
.getSingleResult();
}
}
{code}
JBoss7.0.0:
The user entity returned from the Dao in all 3 methods is managed.
JBoss7.1.0.ALPHA (with AS7-1663 fix):
getUserNoTx():
User is not managed ( case (a) of 7.6.3.1, see my post from 25.08.2011)
getUserTx():
The Dao returns a user entity, but when the entity manager is used after it, an EJBException is thrown.
{quote}
Found extended persistence context in SFSB invocation call stack but that cannot be used because the transaction already has a transactional context associated with it. This can be avoided by changing application code, either eliminate the extended persistence context or the transactional context. See JPA spec 2.0 section 7.6.3.1.
{quote}
getUserTxXpcPropagated()
The entity manager is used before calling the Dao. The Dao returns the same user entity as selected before in the SFSB. The entity is managed.
I think the change for getUserNoTx() is okay, but not for getUserTx() and getUserTxXpcPropagated().
Kind regards,
Gonne
-
9. Re: Synchronization of extended persistence contexts
smarlow Aug 29, 2011 4:42 PM (in response to gonne)I have a local fix for the EJBException (working on the unit test now).
For
getUserTxXpcPropagated(), The extended persistence context should be used for both searches, so I'm not following what is wrong there (not completely sure what you are seeing).
-
10. Re: Synchronization of extended persistence contexts
gonne Aug 29, 2011 5:36 PM (in response to smarlow)Sorry, I was not clear enough. The result for getUserTxXpcPropagated() is the same for both JBoss versions and is okay. I have used this case only for comparison with case getUserTx().
-
11. Re: Synchronization of extended persistence contexts
smarlow Aug 29, 2011 8:28 PM (in response to smarlow)Jira for the EJBException is AS7-1673.
-
12. Re: Synchronization of extended persistence contexts
smarlow Aug 29, 2011 9:20 PM (in response to smarlow)Gonne,
The error check appears to be working (I was wrong about it being broken). An EJBException is supposed to be thrown, if a transactional persistence context is first used in the JTA transaction and then an attempt to bring a extended persistence context into the transaction is made. This is a JPA (7.6.3.1) requirement (as mentioned in the error message):
If the component is a stateful session bean to which an extended persistence context has been bound and there is a different persistence context bound to the JTA transaction, an EJBException is thrown by the container.
https://github.com/scottmarlow/jboss-as/commit/7c7fa408e415ce1bb91963536d83cc0338f75325 contains a unit test for making sure the EJBException is thrown or not.
The fix would be for
getUserTx() to use the "em" before
the "dao", so that the extended persistence context is used for both. When the "em" is used, the extended persistence context will be associated with the transaction (the "dao" will see the extended persistence context in the transaction and use it).
Make sense?
-
13. Re: Synchronization of extended persistence contexts
gonne Aug 30, 2011 10:29 AM (in response to smarlow)Hi Scott,
I think it depends on the interpretation of your quote (7.6.3.1)
{quote}
If a component is called and the JTA transaction is propagated into that component:
• If the component is a stateful session bean to which an extended persistence context has been
bound and there is a different persistence context bound to the JTA transaction, an EJBException
is thrown by the container.
• Otherwise, if there is a persistence context bound to the JTA transaction, that persistence context
is propagated and used.
{quote}
In my case the component called is a SLSB ("TestDaoSLSB") and the JTA transaction of my SFSB ("TestSFSB") is propagated to it. So I would say that the "Otherwise" case applies here and the PC should be propagated.
From my user perspective it is difficult to accept the difference between using the entity manager before a component call or not.
One quote from the hibernate 3.6 documentation, chapter 1.2.4:
{quote}
{quote}
When should a PC be bound to a JTA transaction (at method entry, at first entity manager user,...), is it defined in the specification?
Regards,
Gonne
-
14. Re: Synchronization of extended persistence contexts
smarlow Aug 30, 2011 12:07 PM (in response to gonne)When should a PC be bound to a JTA transaction (at method entry, at first entity manager user,...), is it defined in the specification?
Yes, back to section 7.6.3.1.
7.6.3.1 Requirements for Persistence Context Propagation
Persistence contexts are propagated by the container across component invocations as follows.
If a component is called and there is no JTA transaction or the JTA transaction is not propagated, the
persistence context is not propagated.
If an entity manager is then invoked from within the component:
- Invocation of an entity manager defined with PersistenceContextType.TRANSACTION will result in use of a new persistence context (as described in section 7.6.1).
- Invocation of an entity manager defined with PersistenceContextType.EXTENDED will result in the use of the existing extended persistence contextbound to that component.
- If the entity manager is invoked within a JTA transaction, the persistence context will be bound to the JTA transaction.
The above covers the PC getting bound to the JTA transaction. The first bullet item below, covers the error condition.
If a component is called and the JTA transaction is propagated into that component:
- If the component is a stateful session bean to which an extended persistence context has been bound and there is a different persistence context bound to the JTA transaction, an EJBException is thrown by the container.
- Otherwise, if there is a persistence context bound to the JTA transaction, that persistence context is propagated and used.
The above requirements are important for certain cases, like if the PC (bound to the transaction) has pending changes, the changes should be visible to other code that runs in the same transaction. If multiple persistence contexts (for the same PU name), were allowed to be bound to the transaction, pending changes wouldn't always be visible to other code running in the same transaction (using the same PU name).