Being in EJB and JPA world using CMT (Container Managed Transactions) is very comfortable. Just define few annotations to demarcate transaction boundary (or use the defaults) and that’s it – no fiddling with manual begin, commit or rollback operations.
One way to rollback your transaction is to throw non-application exception (or application exception with rollback = true) from your EJB’s business method.
It seems simple: if during some operation there is a possibility that an exception will be thrown and you don’t want to rollback your tx than you should just catch this exception and you’re fine. You can now retry the volatile operation once again within the same, still active transaction.
Now its all true for application exceptions thrown from user’s components. The question is – what with exceptions thrown from other components? Like JPA’s
EntityManager throwing a
And that’s where the story begins.
JPA specification defines few types of EntityManagers / Persistence Contexts. We can have:
- extended and transactional-scoped EntityManagers,
- container-managed or application-managed EntityManagers.
- JTA or resource-local EntityManager,
Besides the above distinction, we also have two main contexts in which EntityManager / Persistence Context can exist – Java EE and Java SE. Not every option is available for Java EE and not every is possible in Java SE. In the rest of the post I refer to the Java EE environment.
Ok, so before we’ll proceed to the real topic of this post — which is the behaviour of the EntityManager in Java EE created manually using EntityManagerFactory — let’s just shortly describe the above EM types.
Few days ago I’ve created a simple interceptors spike-solution at Github. Its purpose was to show my colleagues that in the EJB’s interceptors you can implement a code that exists in the same transaction and the same security context as the called EJB business method. Moreover, you can benefit from all the dependency injection you need.
This project uses the following resources injected by the Application Server:
TransactionSynchronizationRegistry – used for getting current transaction key and checking if we’re in the same transaction (I’ve written about it e.g. here),
SessionContext – for reading user’s principal – user’s security context is also available in the interceptor,
EntityManager – to persist some data before invoking the business method; it exists in the same transaction as the called method, so either both: the interceptor persistence and business method ends with success or both of them will be rolled-back.
This example also shows how easily you can add RESTful Web Service to your application (take a look at com.piotrnowicki.interceptors.web package).
It also shows that you can define interceptors in the deployment descriptor – without recompilation of your code. Such interceptors will be invoked for every business method in the given module (assuming no exclusion through annotation or DD occurs). An alternative is to define what beans or methods should be intercepted.
Recently, I’ve bumped into few posts on StackOverflow where people tend to compare container managed
EntityManager instances (so the one injected by the container) by invoking
EntityManager#toString() method. I’ve felt that it’s fundamentally wrong to compare
EntityManager instances without knowing how they’re managed by the JPA provider or the Server Application. And what if this behaviour differs between Application Server vendors?
The JPA provider provides an implementation of
EntityManager – that’s obvious. More interesting is that the Application Server is scanning all
@PersistenceContext fields and wrapping these
EntityManagers into its own class – a proxy – which delegates requests to the JPA provider’s
EntityManager. Therefore, if you’re comparing results of
toString() method of such
EntityManagers, you can’t say about
PersistenceContexts equality but rather about Server Application EntityManager equality.
Needless to say, an Application Server could use one proxy as an access point to different
EntityManagers. Without knowing the internals, you’re not able to say how it will work and decide if your results are meaningful.