2

我正在使用 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);
    }
}

但是,相同的 EntityManager 实例被注入到每个 DAO 中。为了进行设置,我使用了 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。注射器本身是在我的主线程中创建的......这可能是问题吗?

4

2 回答 2

2

这是一个非常相似的问题:Guice 如何将单例和非单例注入到多个线程中

对于您的 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 持久性模块或创建自定义 EntityManager 提供程序,它将为每个 get() 调用返回新的 EntityManager,也可以使用 ThreadLocal 实现以确保 EntityManager 将在线程之间共享。

于 2013-07-29T10:32:16.357 回答
0

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

如果您查看EntityManagerProvider 的源代码,您会看到有一个ThreadLocal<EntityManager>. 所以默认情况下,每个线程都应该有自己的EntityManager. 这让我相信问题出在其他地方。您确定没有模块将其设置EntityManager为单例吗?您如何确定所有EntityManagers 都是同一个对象?每个 DAO 肯定都在自己的线程上?您能否提供有关如何在模块中配置 FooDao 以及如何为每个线程提供新 FooDao 的详细信息?

此外,您应该可以将构造函数编写为:

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

Guice 将为您确定EntityManagerProvider提供EntityManager实例的魔力,并将调用get()EntityManagerProvider实例以获取一个EntityManager以提供给您的构造函数。

于 2012-08-26T18:10:27.233 回答