【问题标题】:jpa2 reuses entityManager with guicejpa2 使用 guice 重用 entityManager
【发布时间】:2014-05-06 19:37:38
【问题描述】:

我有一个 Web 应用程序有一些奇怪的行为,我无法真正解决。 我的问题的核心是我的休息端点返回的值存在不一致的行为。 当我启动我的应用程序时,每次调用此端点时,我的查询都会返回相同的值。当我更新一个实体时,我的实体管理器开始表现得很奇怪。现在我的查询开始返回不同的结果。有一次它返回旧值而不是数据库中的值,或者我的结果列表包含代理而不是对象(混合)。

我已验证我的 @transaction 方法放置正确,并且在我的调试堆栈中,我看到了事务拦截器,并且根据对后端的请求创建了实体管理器(因此没有 guice 持久性过滤器)

我的感觉表明问题出在会话上下文中。我有一种感觉(但我无法真正理解)它在多个请求上重用了我的持久性上下文。

我已经将一些框架放在一起以使这一切正常工作。我使用 resteasy 作为 jax-rs 实现者。 guice (4.0beta4) 作为 cdi 实现者,hibernate 作为 jpa 实现者。 因为我们在注入 entitymanager 时需要使用提供程序(因为每个事务都会创建 entitymanager),所以我将其包装在 EntityManagerProxy 中。该类实现了EntityManager接口并将所有方法委托给provider.get().method()。

public class EntityManagerProxy implements EntityManager {
    private final Provider<EntityManager> entityManagerProvider;

    @Inject
    public EntityManagerProxy(final Provider<EntityManager> entityManagerProvider) {
        this.entityManagerProvider = entityManagerProvider;
    }

    private EntityManager getEntityManager() {
        return entityManagerProvider.get();
    }

    @Override
    public void persist(final Object entity) {
        getEntityManager().persist(entity);
    }
}

我的 guice 模块是这样的

public class OptiWEEEModule extends ServletModule implements Module {
    @Override
    protected void configureServlets() {

        super.configureServlets();
        bind(EntityManagerProxy.class);
        // JPA
        install(new JpaPersistModule("myPU"));
    }
}

我知道这是一个模糊的问题,但有人可以帮助我朝着正确的方向前进吗?这不是我可以提供错误消息的真正问题。

编辑:我现在指出了问题所在。使用探查器,我查看了实体上下文被 guice 重用。这意味着它不是每次都执行查询,而是使用现有的实体管理器,应该在每次传递@transactional 注释时创建。

【问题讨论】:

  • 我刚刚从 guice 4beta4 降级到 guice 3 并且发生了同样的错误。
  • @Transactional 的想法是你得到一个新的事务,而不是一个新的 EntityManager。后者也可以处理其中的几个。您没有显示代理的“更新”部分,也没有显示 Web 服务,因此很难说到底是什么导致了您的问题。
  • 我实际上深入研究了这个问题。不是更新部分破坏了我的应用程序,而是在每个线程上重用了实体管理器。我想我正在创建一个包含我的 entitymanager 的单身人士。我的 entitymanagerproxy 会导致这种情况吗?这是我遵循的策略code.google.com/p/google-guice/wiki/…
  • This question 听起来很相似。
  • @mabi 这个问题确实很相似,但我已经在每个点都注入了一个提供程序

标签: java jpa-2.0 guice resteasy guice-persist


【解决方案1】:

我从邮件列表中得到了这个遮阳篷。

Guice perstist 有一个相当不寻常的功能,它会导致一些 问题。我想你可能只是击中它

当您请求工作单元之外的实体经理时 persist 将为您隐式启动工作单元。很遗憾 UnitOfWork 上的 isActive() 是包私有的。你不能测试 如果某个工作单元处于活动状态。

有两种方法可以显式地开始和结束一个工作单元。你可以 使用 UnitOfWork 和方法 begin() 和 end()。还有 @Transactional 注释启动一个工作单元。 @Transactional 将 当且仅当它开始时,也结束工作单元。

最佳做法是仅在 @Transactional 方法。

我只能得出结论,@Transaction 注释的成熟度与 spring 中的不一样。另一方面,通过提供者在@Transactional 管理器中获取实体管理器并不能真正解决这个问题。

由于我们很快就要投入生产,所以我已经切换回 Spring,这很遗憾,但这是管理我们最后期限的唯一明智的解决方案。

【讨论】:

    猜你喜欢
    • 2012-04-29
    • 2015-05-01
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多