What happens in this scenario is determined by:
- JPA resilience context and its relation to JTA transactions.
- Javas' pass-by-reference "behavior as a parameter passing through local interfaces. (See Note on link passing at the end of this answer)
Creating an Entity Manager with the @PersistenceContext annotation @PersistenceContext Manager and the associated persistence context defined by your persistence.xml file. The context will track objects of types specified in your persistence.xml . An entity becomes manageable in this context after being saved, found ( em.find() ), or merged. The context will be associated with the current JTA transaction. When this transaction ends, changes that exist in the save context can be discarded and committed - or canceled if the transaction itself is rolled back.
The sample script uses the local Bean2s interface. When Bean2-MethodB is called, a new transaction is triggered because the method is annotated with @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) . Caller transaction suspended. The persistence context is not associated with a newly created transaction. However, the object that has passed will refer to the same instance of the object being processed by Bean1-MethodA , and this instance is a managed object in the context of the persistence of Bean1s Entity Manager. Thus, although the transaction associated with this persistence context is suspended, there are no restrictions on modifying this object from another transaction.
So, the nominal sequence of events:
- Called
Bean1-MethodA , TransactionA is launched.- Transaction Entity Agent created, persistence context associated with TransactionA.
Bean1-MethodA calls Bean2MethodB and passes the object as a parameter.- New transaction - TransactionB starts, the transaction is suspended.
Bean2-MethodB changes the entity.name field.- Bean2-MethodB completes and the transaction is taken.
- TransactionB JTA persistent resources commit - the entity is in the persistence context associated with TransactionA and therefore is not executed.
- Bean1-MethodA resumes, as does the associated TransactionA.
- Entity changes made in
Bean2-MethodB visible to Bean1-MethodA and persistence context Bean1-MethodA ends, TransactionA transaction and persistence changes are discarded / transferred to DB- → DB contains field change made in
Bean2-MethodB
What happens when a Bean2-MehodBs transaction returns?
It is worth noting that if changes to entity fields are made in Bean2-MethodB and Bean2-MethodB's transactions in the reverse order, changes to class fields are not returned. Any JTA resources will be rolled back, but changes to the entity field will still be reflected in the database. If Bean1-MehodA succeeds, leading to potential inconsistencies. Perhaps problems with the real world may force such a solution, but it is probably better to modify the objects in the transaction that can discard these changes.
The above scripts have been tested on eclipse-mars / WildFly8.2 / HibernateJPA / Derby
Working with remote EJB calls
Here, the entity parameter is serialized, which leads to copying the object to Bean2-MethodB . This copy is not the same object as in Bean1-MethodA , it is a separate object and is not shared with Bean1-MethodA . (This is sometimes called a skip; see the note at the end of this answer). In order for the changes to be reflected in the context of Bean1-MethodA's persistence, the object had to be returned to Bean1-MethodA , and then merged in the persistence context using Entity Manager. This merge would be required regardless of whether the remote ejb call was deleted as part of the transaction.
Note on "Pass by reference" and "Pass by value".
All parameters in java are passed by definition by definition. For a good extended discussion on stack overflows, see Is Java a “Missing Link”, etc. or "pass by value" . The important thing is that for local interfaces, Java passes a copy of the link - a pointer - to the shared instance - and this is what people often understand as a “cross reference”. Remote interfaces create a copy of an entity instance at the remote end, so the calling method does not show any changes to this copy. This is sometimes referred to as passing by value.