6

我有一个 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 注释时都应该创建它。

4

1 回答 1

1

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

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

当您在工作单元之外请求实体管理器时,guice persist 将隐式地为您启动工作单元。不幸的是,UnitOfWork 上的 isActive() 是包私有的。而且您无法测试某个工作单元是否处于活动状态。

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

最佳做法是仅在 @Transactional 方法中获取实体管理器。

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

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

于 2014-06-18T06:53:39.333 回答