Guice在多线程应用程序中注入了EntityManager

时间:2012-08-26 08:04:37

标签: java jpa guice

我正在使用Java SE 7开发桌面应用程序。该应用程序使用多个线程,并且在创建的每个线程中注入DAO类以访问我的数据库。作为持久层,我正在使用EclipseLink和JPA。使用构造函数注入将EntityManager注入到我的DAO类中,因为它不是线程安全的,所以我使用这样的Provder来实现这个方法:

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);
    }
}

但是,每个DAO都注入了相同的EntityManager实例。为了设置它,我使用了由guice提供的JpaPersistModule,我确信到目前为止我的设置中没有单例。

有人知道如何告诉guice在注入时创建EntityManager的新实例吗?

在另一种方法中,我尝试了EntityManagerFactory和EntityManager的自定义提供程序,并将JpaPersistModule从我的业务中删除。这导致了每个DAO的EntityManager实例,但是@Transactional带注释的方法当时没有被截获。

我很感激这个问题的任何解决方案。 谢谢到目前为止!

---编辑---

将DAO类注入到正在使用它们的Runnable中。 Runnable也通过Provider提供。我的模块配置如下所示:

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;
    }
}

这里PluginMonitor是我的Runnable。 Injector本身是在我的主线程中创建的......可能这是问题吗?

2 个答案:

答案 0 :(得分:2)

这是一个非常类似的问题:How Guice injects singletons and non-singletons into multiple threads

对于你的DAO,这应该有效。

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);
    }
}

您应该使用Jpa Persistence Module或创建自定义EntityManager提供程序,它将为每个get()调用返回新的EntityManager,也可以使用ThreadLocal实现,以确保将跨线程共享EntityManager。

答案 1 :(得分:0)

我不熟悉JPA,但希望我仍然可以提供帮助: - )

如果您查看the source for EntityManagerProvider,就可以看到ThreadLocal<EntityManager>。因此,默认情况下,每个线程都应该有自己的EntityManager。这让我相信问题出在其他地方。您确定没有模块将EntityManager设置为单身吗?你如何确定所有EntityManager是同一个对象?每个DAO肯定都在自己的线程上?您能否详细说明如何在模块中配置FooDao以及如何为每个线程提供新的FooDao?

另外,您可以将构造函数编写为:

@Inject
public FooDao(EntityManager emp) {
    this.em = emp;
}

Guice会帮助您确定EntityManagerProvider提供EntityManager个实例,并会在get()个实例上调用EntityManagerProvider以获得EntityManager给你的构造函数。