We use Guice Persist to inject EntityManager in our project.
E.g.
public class MyDao{
@Inject
EntityManager em;
public void someMethod(){
I'm injecting a provider .... but I suspect something is wrong. When I try to redeploy an application ALWAYS I have to restar the server because the JPA classes are cached.
It happens the following pseudo-bug
https://bugs.eclipse.org/bugs/show_bug.cgi?id=326552
Theoretically by injecting a Provider and getting an instance of EntityManager you should not close anything ....
Even though the question is perfectly answered by Piotr I'd like to add some practical advise on how to use guice-persist.
I've been having issues with it which were pretty hard to debug. In my application certain threads would display outdated data and sometimes EntityManager
instances were left with old dead database connections. The root cause was to be found in the way I used the @Transactional
annotation (I only used them for methods that do updates/inserts/deletes, not for read-only methods). guice-persist stores EntityManager
instances in a ThreadLocal
as soon as you call get()
on an injected Provider<EntityManager>
instance (which I did for read-only methods). However, this ThreadLocal
is only removed if you also call UnitOfWork.end()
(which normally is done by the interceptor if @Transactional
is on the method). Not doing so will leave the EM instance in the ThreadLocal so that eventually every thread in your thread pool will have an old EM instance with stale cached entities.
So, as long as you stick to the following simple rules the usage of guice-persist is straight forward:
Provider<EntityManager>
instead of EntityManager
directly.@Transactional
(even the read-only methods). This way the JpaLocalTxnInterceptor
will intercept the calls to your annotated methods making sure not only to start and commit transactions but also to set and unset EM instances in the ThreadLocal.PersistFilter
servlet filter that ships with guice-persist. It will call begin()
and end()
on the UnitOfWork
for you before and after the request is done, thereby populating and cleaning up the ThreadLocal.Hope this helps!
1. It depends on you module cofiguration. There are some basic bindings:
JpaPersistanceService
public class JpaPersistanceService implements Provider<EntityManager> {
private EntityManagerFactory factory;
public JpaPersistanceService(EntityManagerFactory factory) {
this.factory = factory;
}
@Override
public EntityManager get() {
return factory.createEntityManager();
}
}
Module binding
EntityManagerFactory factory = Persistence.createEntityManagerFactory(getEnvironment(stage));
bind(EntityManager.class).annotatedWith(Names.named("request")).toProvider(new JpaPersistanceService(factory)).in(RequestScoped.class);
bind(EntityManager.class).annotatedWith(Names.named("session")).toProvider(new JpaPersistanceService(factory)).in(SessionScoped.class);
bind(EntityManager.class).annotatedWith(Names.named("app")).toProvider(new JpaPersistanceService(factory)).asEagerSingleton;
Usage
@Inject @Named("request")
private EntityManager em; //inject a new EntityManager class every request
@Inject @Named("session")
private Provider<EntityManager> emProvider; //inject a new EntityManager class each session
//This is little bit tricky, cuz EntityManager is stored in session. In Stage.PRODUCTION are all injection created eagerly and there is no session at injection time. Session binding should be done in lazy way - inject provider and call emProvider.get() when em is needed;
@Inject @Named("application")
private EntityManager em; //inject singleton
2. Yes, you should or you will use JpaPersistModule [javadoc]
3. Well, this is about JPA configuration in persistence.xml and EntityManager scope
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)