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.

One of the ways to cope with this problem might be to unwrap the container-provided EntityManager proxy to get to the JPA-provided one. You can do that either using:
- EntityManager#getDelegate() which returns an Object (this is the depreciated way) or,
- EntityManager#unwrap(JPAProviderSpecificClass) which returns JPA-provider specific object (encouraged way).
In this way you’re one step closer to the victory.

On this point, it’s worth of noticing, that by the JPA specification, given Persistence Context, when used in transactional environment, is bound to exactly one transaction and is accessible from all components which participates in this transaction. So, maybe we could just compare if the transaction is the same and it would be enough to confirm that the PersistenceContexts are the same? You could check transactions for equality using TransactionSynchronizationRegistry#getTransactionKey().

Both situations: unwrapping of EntityManager and testing transactions for equality, have been presented in following code.

Moreover, this code shows one more, very important thing which might be hard to analyse. In order to invoke EJB call, you need to use it’s business interface. If you don’t do that, you’ll end invoking a local method call which doesn’t have any EJB nature – the container is not able to intercept such method invocation. Therefore, for local call, the @TransactionAttribute will have no meaning.

Take a look at the following code. I’m using EclipseLink and Glassfish 3.1.1. The client invokes method1().

Lets examine the exemplary results of the invocation:

INFO: [method1] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@173d62d

INFO: [method1] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@1f243df

INFO: [method1] Tx key: JavaEETransactionImpl: txId=45 nonXAResource=23 jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@462718, com.sun.enterprise.resource.pool.PoolManagerImpl$SynchronizationListener@1b0d75f]

INFO: [method2] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@10ba812

INFO: [method2] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@475614

INFO: [method2] Tx key: JavaEETransactionImpl: txId=46 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@1644679]

INFO: [method2] Is Tx1 the same as Tx2? false

We have 2 separate transactions (result of comparison – false).
Application Server EntityManager wrappers — in method1() and method2() — represents different instances.
JPA provider EntityManagers also represents different instances.

Now let’s modify the code a bit and remove or comment the @TransactionAttribute fragment, so method2() will have a default Tx attribute – REQUIRED. In this case, it will reuse the transaction of method1(). Let’s look at the results:

INFO: [method1] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@178fd24

INFO: [method1] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@33517f

INFO: [method1] Tx key: JavaEETransactionImpl: txId=48 nonXAResource=95 jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@12b86b2, com.sun.enterprise.resource.pool.PoolManagerImpl$SynchronizationListener@985158]

INFO: [method2] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@469bc

INFO: [method2] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@33517f

INFO: [method2] Tx key: JavaEETransactionImpl: txId=48 nonXAResource=95 jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@12b86b2, com.sun.enterprise.resource.pool.PoolManagerImpl$SynchronizationListener@985158]

INFO: [method2] Is Tx1 the same as Tx2? true

We have 1 transaction (result of comparison – true).
Application Server EntityManager wrappers represents different instances.
Both JPA provider EntityManagers represents the same instance.

So, as you can see – only after unwrapping the container-provided EntityManager we were able to see that we, in fact, use the same EntityManager.

At the end, let’s see get back to the original code but change the invocation of method2() from method1() to be a local call, so we’ll be using myMethod2(txKey) instead of ctx.getBusinessObject(MyEJB.class).myMethod2(txKey). Exemplary results might be as follows:

INFO: [method1] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@110d926

INFO: [method1] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@12062da

INFO: [method1] Tx key: JavaEETransactionImpl: txId=50 nonXAResource=95 jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@139defe, com.sun.enterprise.resource.pool.PoolManagerImpl$SynchronizationListener@5f299d]

INFO: [method2] Server proxy for EntityManager EM: com.sun.enterprise.container.common.impl.EntityManagerWrapper@110d926

INFO: [method2] EclipseLink EntityManager: org.eclipse.persistence.internal.jpa.EntityManagerImpl@12062da

INFO: [method2] Tx key: JavaEETransactionImpl: txId=50 nonXAResource=95 jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@139defe, com.sun.enterprise.resource.pool.PoolManagerImpl$SynchronizationListener@5f299d]

INFO: [method2] Is Tx1 the same as Tx2? true

We have 1 transaction (result of comparison – true).
Both Application Server EntityManager wrappers represents the same instance.
Both JPA provider EntityManagers represents the same instance.

I hope this sum up what are possible situations you might bump into when using transactional, container-managed EntityManager.

The code snippet which I presented here can be found on my Gist.

References:
- EclipseLink Forum
- Glassfish mailing list

Did you like this? Share it:

8 thoughts on “Am I in the same transaction? Am I using the same PersistenceContext?

  1. Thank you. Your post is very helpful.
    One question: Do you know why two EntityManager instances created by the same factory within the same bussness method execution behave differently on entities loaded by one of them. At least, the EntityManager#contains(Object) operation returns true when the EntityManager that loaded the entity (by means of a Query) is used, and return false with the other.
    I ask this because, according to what I understood from the specification, both EntityManagers are associated to the same persistence context, and, therefore, should be interchangeable. Am I wrong?

    Reply
    • Hello Gustavo,

      Let’s nail this thing :-) Can you post some exemplary code e.g. on gist to be 100% we’re talking about the same thing? It will also be easier to make some tests on different implementors.

      Cheers and thanks for your comment!

      Reply
      • Hello Piotr,
        I read the specification again to discover that what I understood before was wrong. The EntityManagers created by a common EntityManagerFactory doesn’t share the same persistence context as I wrongly understood. Each of them have its own associated persistence context.
        That is a bad thing because EntityManager isn’t thread safe and, therefore, I have to do extra work to avoid concurrency issues.
        Cheers and thanks for your answer.

        Reply
  2. Great post!
    I’m using jboss and cmt and have seen strange behaviour when using requires_new on an ejb method that I loop over to insert some records. I see that intermittently after restarting the jboss the operations in the method aren’t committed to db after the method is finished.
    So, I have tried to use the great TransactionSynchronizationRegistry method and found that when the data isn’t committed I actually don’t get a new transaction each time the method is entered. So how to continue the debugging after finding out that the transactionsactually are the same?

    Reply
    • Hello Mikael,

      Can you produce the simpliest possible code that shows your problem? Ideally you could post it on gist so we’d be able to solve this together.

      If you’re invoking other business methods from one component, did you check method invocation (that it’s using EJB proxy, as discussed in the article?)

      Cheers!
      Piotr

      Reply
  3. Hello Piotr, very good article, it shows deep understanding of yours. I’ve been preparing for JPA Exam myself, I find it very helpful.

    A valuable addition to this post could be some example with a call to another bean within the same transaction. As I understand, we’d see same transaction, different wrapper, and different entity manager.

    Cheers :)

    Reply
    • Thanks a lot for kind words mate!

      If you’d like to test some other cases – feel free to do so or send some pull request to the exemplary code on the github.

      Best,
      Piotr

      Reply

Leave a reply

required


*

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>