jpaguiceentitymanagerguice-persist

Does Guice Persist provide transaction scoped or application managed EntityManager?


We use Guice Persist to inject EntityManager in our project.

E.g.

public class MyDao{
   @Inject
   EntityManager em;

   public void someMethod(){
       //uses em instance
   }
}

But it is unclear for us how injected instance of EntityManager is about to be used.

  1. What type of EntityManager is this? (see e.g.: types of entity managers) Under the hood Guice Persist instantiates it via EntityManagerFactory.createEntityManager() so I'd say it's application-managed entity manager. But in official Wiki they write about seesion-per-transaction strategy, which suggests that EntityManager is (pseudo) transaction-scoped.
  2. Should we invoke close() on it manually? Or Guice will take care of it?
  3. What is the scope of first level cache? Only single transaction (like in transaction-scoped entity managers) or as long as I use the same injected instance of EntityManager (like in application managed entity managers)?

Solution

  • I did some research of the source code of Guice-persist and read through comments under Guice-persist wiki pages and these are the answers that I needed:

    1 . Lifecycle management of EntityManager is kind of broken if it's injected via @Inject EntityManager. As stated in one of the comments on the Wiki:

    I confirm that inject directly an EntityManager instead of a provider can be dangerous. If you're not inside a UnitOfWork or a method annotated with @Transaction, the first injection of an EntityManager in a thread will create a new EntityManager, never destroy it, and always use this specific EntityManager for this thread (EM are stored thread-local). This can lead to terrible issues, like injection of dead entityManager (connection closed, etc) So my recommendation if to always inject a Provider, or at least to inject directly an EntityManager only inside an opened UnitOfWork.

    So example in my question isn't the most correct usage. It creates singleton instance of EntityManager (per-thread) and will inject this instance everywhere :-(.

    However if I've injected Provider and used it inside @Transactional method then the instance of EntityManager would be per-transaction. So the answer to this question is: if injected and used correctly, the entity manager is transaction-scoped.

    2 . If injected and used correctly then I don't need to manualy close entity manager (guice-persist will handle that for me). If used incorrectly, closing manually would be very bad idea (closed instance of EntityManager would be injected in every place when I @Inject EntityManager )

    3 . If injected and used correctly then the scope of L1 cache is single transaction. If used incorrectly, the scope of the L1 cache is the lifetime of application (EntityManager is singleton)