Reputation: 1016
I'm working on a desktop application using Java SE 7. The application uses multiple threads and in each thread that is created a DAO class is injected to gain access to my database. As persistence layer i'm using EclipseLink and JPA. The EntityManager is injected into my DAO class using constructor injection and since it is not thread safe, I went for the approach using a Provder like this:
public PluginInstanceJpaController implements IPluginInstanceDao {
private EntityManager em;
@Injected
public PluginInstanceJpaController(Provider<EntityManager> emp) {
this.em = emp.get();
}
@Transactional
public void create(PluginInstance foo) throws Exception {
em.persist(foo);
}
}
However, the very same EntityManager instance is injected into each DAO. For setting that up I used the JpaPersistModule as it is provided by guice and i'm sure that there are not singletons in my setup so far.
Does anyone know how to tell guice to create a new instance of the EntityManager when injecting?
In another approach I tried custom providers for the EntityManagerFactory and the EntityManager and leaving the JpaPersistModule out of my business. This resulted in a EntityManager instance per DAO, however @Transactional annotated methods were not intercepted then.
I'd appreciate any solution to this issue. Thanks so far!
--- EDIT ---
The DAO classes are injected into a Runnable that is using them. The Runnable is also provided through a Provider. My module configuration looks something like this:
public class RepositoryModule extends AbstractModule {
@Override
protected void configure() {
// DAO bindings
bind(IObjectStoreDao.class).to(ObjectStoreJpaController.class);
bind(IPluginInstanceDao.class).to(PluginInstanceJpaController.class);
}
@Provides
public PluginMonitor newMonitor(IPluginInstanceDao plugDao, IObjectStoreDao osDao) {
PluginMonitor m = new PluginMonitor();
m.setPluginInstanceDao(plugDao);
m.setObjectStoreDao(osDao);
return m;
}
}
Here PluginMonitor is my Runnable. The Injector itself is created in my main thread... might this have been the issue?
Upvotes: 2
Views: 4847
Reputation: 4232
This is very similiar issue: How Guice injects singletons and non-singletons into multiple threads
To your DAO, this should work.
public PluginInstanceJpaController implements IPluginInstanceDao {
private Provider<EntityManager> emProvider;
@Injected
public PluginInstanceJpaController(Provider<EntityManager> emp) {
this.em = emp;
}
@Transactional
public void create(PluginInstance foo) throws Exception {
em.get().persist(foo);
}
}
You should use Jpa Persistence Module or create custom EntityManager provider, which will return new EntityManager for each get() call, also it can be implemented with ThreadLocal to ensure EntityManager will be shared across thread.
Upvotes: 2
Reputation: 1178
I'm not familiar with JPA, but hopefully I can still help :-)
If you look at the source for EntityManagerProvider, you can see there's a ThreadLocal<EntityManager>
. So by default, each thread should have its own EntityManager
. That leads me to believe the problem is elsewhere. Are you sure that no module is setting the EntityManager
to be a singleton? How are you determining that all the EntityManager
s are the same object? Each DAO is definitely on its own thread? Can you provide details on how FooDao is configured in your module and how a new FooDao is provided to each thread?
Also, you should be fine to write your constructor as:
@Inject
public FooDao(EntityManager emp) {
this.em = emp;
}
Guice will do the magic for you of determining that EntityManagerProvider
provides EntityManager
instances, and will call get()
on the EntityManagerProvider
instance to get an EntityManager
to give to your constructor.
Upvotes: 0