EJB/JPA Transaction Boundaries

情到浓时终转凉″ 提交于 2021-02-18 11:17:10

问题


I was reading EJB Transaction boundary and Transaction boundary

Lets concentrate on RequiresNew Attribute.

Here is the modified diagram from the link

enter image description here

So let say method-B is annotated with RequiredNew attribute.

so according to theory when method-A calls method-B a new transaction will be start and the already started transaction will be suspended, and when method-B returns the new transaction will be committed.


Now consider that in section S1 we create a jpa entity using entitymanager.persist() and now we pass this entity to method-B which set the name field of the entity.

Now when we return from method-B how can it commit the transaction as in db, the entity is not being committed by the suspended transaction started by method-A ?


PS: Db running in read-committed isolation level.


回答1:


What happens in this scenario is governed by:

  1. The JPA Persistence Context and its relationship to JTA transactions.
  2. The behaviour of Java’s “pass-by-referencelike parameter passing on local interfaces. (See note on pass-by-reference at the end of this answer)

Creating an Entity Manager with the @PersistenceContext annotation leads to the creation of a Transaction-Scoped entity manager and associated persistence context as defined by your persistence.xml file. The context will keep track of the entities of the types specified in your persistence.xml. An entity becomes managed in that context after it is persisted, found (em.find()) or merged. The context will be associated with the currently running JTA transaction. When this transaction ends, the changes present in the persistence context can be flushed and committed - or rolled-back if the transaction itself rolls back.

In the example scenario assume Bean2’s local interface is used. When Bean2-MethodB is called a new transaction is started since the method is annotated with @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW). The transaction of the calling method is suspended. No persistence context is associated with the newly created transaction. However, the entity passed in will refer to the same instance of the entity processed by Bean1-MethodA, and this instance is a managed entity in the persistence context of Bean1’s Entity Manager. So, even though the transaction associated to this persistence context is suspended, there are no restrictions on modifying that entity from within another transaction.

So, the nominal sequence of events is;

  1. Bean1-MethodA is called, TransactionA starts.
  2. Transaction-Scoped Entity Manager created, persistence context associated with TransactionA.
  3. Bean1-MethodA calls Bean2MethodB and passes in ’entity’ as a parameter.
  4. New Transaction – TransactionB starts, TransactionA suspended.
  5. Bean2-MethodB modifies field entity.name.
  6. Bean2-MethodB finishes and TransactionB commits.
  7. TransactionB JTA persistent resources commit - entity is in persistence context associated with TransactionA and so is not committed.
  8. Bean1-MethodA resumes as does its associated TransactionA.
  9. Entity changes made in Bean2-MethodB are visible to Bean1-MethodA and the persistence context
  10. Bean1-MethodA finishes, TransactionA commits and persistence context changes are flushed/committed to DB
  11. --> DB contains field change made in Bean2-MethodB

What happens when Bean2-MehodB’s Transaction rolls-back?

It is worth noting that if entity field changes are made in Bean2-MethodB, and Bean2-MethodB’s transaction rolls-back, changes to class fields are not reverted. Any JTA resources will be rolled-back, but the entity field changes would still be reflected in the DB If Bean1-MehodA completes successfully, leading to potential inconsistencies. It maybe that real world problems might force such a solution, but probably better to modify entities in the transaction that can roll those changes back.

The above scenarios were tested on eclipse-mars/WildFly8.2/HibernateJPA/Derby

Working with Remote EJB calls

Here, the entity parameter is serialised resulting in a copy of the entity in Bean2-MethodB. This copy is not the same object as used in Bean1-MethodA, it is a detached entity and is not shared with Bean1-MethodA. (This is sometimes known as pass-by-value, see note at the end of this answer). In order for changes to be reflected in Bean1-MethodA’s persistence context the entity would need to be returned to Bean1-MethodA and then merged into the persistence context using the Entity Manager. This merging would be required regardless of whether or not the remote ejb call was made within a transaction.

Note on “Pass-by-reference” and “Pass-by-value”.

All parameters in java are pass by value by definition. For a good - extended - discussion on Stack overflow see Is Java "pass-by-reference" or "pass-by-value"?. What’s important here is that for local interfaces, Java passes a copy of the reference – a pointer - to the shared instance – and this is what people often understand as “pass-by-reference”. Remote interfaces create a copy of the entity instance at the remote end so the calling method has no visibility of any changes to this copy. This is sometimes known as pass-by-value.



来源:https://stackoverflow.com/questions/30636273/ejb-jpa-transaction-boundaries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!