我们是否需要在select调用上关闭EntityManager资源

时间:2013-02-14 04:01:48

标签: hibernate jpa

  1. 选择呼叫泄漏连接
  2. EntityManagerFactory emf = Persistence.createEntityManagerFactory("foo");
    EntityManager em = emf.createEntityManager();
    Query query = em.createQuery("select bar from Bar);
    

    我们是否需要在select调用上关闭EntityManager资源,否则会泄漏连接。

4 个答案:

答案 0 :(得分:3)

如果使用EMF创建自己的EntityManager实例,则需要关闭它们。

如果您在manged容器(例如JBoss AS或任何其他EJB容器)中运行,那么您可以将一个EntityManger注入到您的bean中,然后您不必担心关闭它。

答案 1 :(得分:2)

当然,请务必关闭您的EntityManagers。

答案 2 :(得分:2)

我有类似的连接泄漏。根本原因是select语句隐式启动事务。调用EntityManager.close()时,该事务仍处于活动状态,并且由于某种原因使连接保持打开状态。

更糟糕的是,我们的连接池从未收回陷入此状态的连接。

我的修复是在关闭任何entityManager之前显式检查活动事务。我为此写了一个小帮手函数:

public static void rollbackAndClose(EntityManager mgr) {
    if (mgr != null) {
        EntityTransaction transaction = mgr.getTransaction();
        if (transaction.isActive()) {
            transaction.rollback();
        }
        mgr.close();
    }
}

(我习惯在从Oracle或SQLServer断开SQL客户端时自动回滚事务,因此EntityManager行为对我来说是违反直觉的。不确定JPA是否规定了这种行为,或者它是否特定于Hibernate或MySQL 。)

答案 3 :(得分:0)

从您显示的代码段看来,您的应用程序看起来像是独立的,而不是在某些Java EE容器(如JBoss AS或Spring)中运行的托管应用程序(为了参数,可以将其视为Java EE容器)。 根据以下Wiki,您正在应用程序管理的实体管理器中运行。因此,您需要明确关闭实体管理器和工厂。

我想澄清您需要在事务边界关闭EntityManager。如果你看一下hibernate Session的代码(EntityManagerImpl.close()实际委托给session close)。您会注意到它关闭了事务并清除了持久性上下文。关闭EntityManagerFactory更多是在应用程序级别,因此您可以重用它并在销毁应用程序时关闭它。

这样说,并且关注连接泄漏后请注意,连接不是由hibernate直接管理的。 Hibernate有一个插件架构,允许与连接池集成。 Hibernate(我认为从版本3.3开始,不确定)附带了默认的连接池机制,不建议用于生产。如果您使用的是默认值,则可能是导致连接泄漏的原因(请参阅以下post)。

最常见的连接池用于休眠是C3P0(我不确定它是最好的...)。 在非托管环境中,您需要验证连接池的配置(例如,hibernate.c3p0。*相关的hibernates属性)