一尘不染

如何在CDI环境中管理EntityManager生命周期(使用Tomcat)

hibernate

我正在开发一个应用程序,并且已经开始CDIJSF和一起使用JPA。Web容器为Tomcat

我对豆子的EntityManager生命周期感到非常困惑CDI,因此我需要一个很好的建议来清除一些想法。通常,我已阅读的内容EntityManager应主要在Java EE容器中使用,并使用PersistenceContext注释将其注入。因此,然后容器要注意其使用寿命。但是,如果您不使用Java EE容器(如Tomcat),那么我需要管理自己EntityManager的生活。

现在,使用哪种方法是我最好的选择Tomcat, CDI, JSF and JPA?我现在正在做的事情如下:

public class EntityManagerFactoryProducer {

    public static final String TEST = "test";

    @Produces
    @ApplicationScoped
    public EntityManagerFactory create() {
        return Persistence.createEntityManagerFactory(TEST);
    }

    public void destroy(@Disposes
    EntityManagerFactory factory) {
        factory.close();
    }
}

public class EntityManagerProducer {

    @Inject
    private transient Logger logger;

    @Inject
    private EntityManagerFactory emf;

    @Produces
    public EntityManager create() {
        return emf.createEntityManager();
    }

    public void destroy(@Disposes
    EntityManager em) {
        em.close();
        logger.debug(String.format("%s Entity manager was closed", em));
    }
}

@Named
@ViewScoped
@Interceptors(LoggingInterceptor.class)
public class ProductBacking implements Serializable {

    @Inject
    private ProductDAO productDAO;

@ViewScoped
public class ProductDAOImpl implements ProductDAO, Serializable {
    private static final long serialVersionUID = 4806788420578024259L;

    private static final int MAX_RANDOMIZED_ELEMENTS = 3000;

    @Inject
    private transient Logger logger;

    @Inject
    private EntityManager entityManager;

    @Override
    public List<Product> getSuggestedProducts() {
        logger.debug(String.format("%s Entity manager get products", entityManager));

        return entityManager.createQuery("SELECT p FROM Product p ORDER BY random()", Product.class).setMaxResults(
                MAX_RANDOMIZED_ELEMENTS).getResultList();
    }

    @Override
    public void saveProduct(Product product) {
        logger.debug(String.format("%s Entity manager save product", entityManager));

        entityManager.getTransaction().begin();
        entityManager.merge(product);
        entityManager.getTransaction().commit();
    }

    @PreDestroy
    void destroy() {
        entityManager.close();
    }
}

因此,基本上,我只是使用Plain
CDI来完成此操作。但是,我不确定这是否是标准方法,更重要的是,我不知道在EntityManager结束豆寿命后如何关闭。总结:我最终遇到了许多未关闭的连接EntityManager,因此内存泄漏。

有人可以帮助我了解如何继续吗?


阅读 226

收藏
2020-06-20

共1个答案

一尘不染

这与CDI无关。EntityManager的生命周期取决于其类型,可以是:

  1. 容器管理的交易,
  2. 容器管理扩展
  3. 应用程序管理。

前两个仅在功能完善的应用程序服务器中可用。因此,如果您要坚持使用servlet容器,则可以选择第3个选项。

您将必须在应用程序中显式打开和关闭EM。这很简单:创建EntityManagerFactory的应用程序范围的实例,然后将其注入所有bean。当您需要EM时,只需创建它,即可使用它,然后立即关闭,而无需等待bean的上下文结束。因为在此配置中,打开的EntityManager将保留连接,而对于寿命长的bean,您将用尽连接。您可以在ObjectDB手册的“
获取JPA数据库连接”
部分中找到简单而全面的解释。

2020-06-20