Hibernate、C3P0、postgres、Tomcat连接在事务中处于空闲状态

Hibernate、C3P0、postgres、Tomcat连接在事务中处于空闲状态,hibernate,c3p0,Hibernate,C3p0,我们有一个使用Hibernate连接到postgre数据库的应用程序。我们使用C3P0作为连接池 persistence.xml: org.hibernate.ejb.HibernatePersistence ---类别-- 保存对象: 加载对象: @SuppressWarnings("unchecked") public List<Entity> findByProperty(String propertyName, final Object

我们有一个使用Hibernate连接到postgre数据库的应用程序。我们使用C3P0作为连接池

persistence.xml:

org.hibernate.ejb.HibernatePersistence

---类别--












保存对象:

加载对象:

@SuppressWarnings("unchecked")
    public List<Entity> findByProperty(String propertyName, final Object value,
            final int... rowStartIdxAndCount) {

        try {
            final String queryString = "select model from " + clazz.getName()
                    + " model where model." + propertyName + "=     :propertyValue";
            Query query = EntityManagerHelper.getEntityManager().createQuery(
                    queryString);
            query.setParameter("propertyValue", value);
            if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0)     {
                int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
                if (rowStartIdx > 0) {
                    query.setFirstResult(rowStartIdx);
                }

                if (rowStartIdxAndCount.length > 1) {
                    int rowCount = Math.max(0, rowStartIdxAndCount[1]);
                    if (rowCount > 0) {
                        query.setMaxResults(rowCount);
                    }
                }
            }
            final List<Entity> result = query.getResultList();
            return result;
        } catch (RuntimeException re) {
            re.printStackTrace();
            throw re;
        }
    }  

谢谢你的帮助!:)

我觉得您的配置不正确:

  • transaction type=“RESOURCE\u LOCAL”表示您不在JTA环境中
  • property name=“hibernate.connection.release\u mode”value=“after\u statement”与auto commit=false结合使用非常少见
  • “after_statement”只能在连接提供程序支持主动版本(并且能够为同一事务中的每个语句返回相同的连接)的情况下使用

    hibernate可能会忽略AFTER_语句(因为hibernate检测到此发布模式与您的设置不兼容),而使用AFTER_事务。。。但是为了确保你没有错误地使用它,你把

     <property name="hibernate.connection.release_mode" value="auto" />
    
    
    
    这将在非JTA环境中设置AFTER_事务发布模式

    我不确定这是否能解决您的问题(因为您可能已经在after_事务模式下运行)。(如果无法修复,请发表评论,并进行更深入的调查)

    编辑

    顺便说一句,重建sessionFactory似乎很奇怪。SessionFactory通常是单例的,SessionFactory的主要目的是非常高效地构建新会话。一般来说,没有理由重新创建它(因为sessionFactory只依赖于静态数据,这既耗时又无用)

    我可以看到重新创建sessionFactory的唯一原因是,如果您的应用程序在运行时更改了数据模型,即创建新表或列,那么新的会话工厂将看到这些更改,前提是您同时应用程序修改映射文件或字节码,以添加新的注释、字段和类。我想你没有那样做

    编辑2

    正如我在上一次编辑中所说:避免重建sessionFactory。将此方法设置为私有,以确保不会多次调用它。如果代码正在重新构建sessionFactory,则可能是问题的原因,因为新的sessionFactory可能会消耗一些连接(由于相关的C3PO设置)

    另外一点:你说过当禁用延迟加载时:再也没有问题了。因此,这个问题也可能是由于为延迟加载而创建的会话没有正确关闭造成的。尝试调试延迟加载操作,以查看会话来自何处,以及会话是否已关闭


    编辑3(作为对您上次评论的回复)

    您面临着一个非常常见的架构设计问题,假设有两种方法可以解决它。好的和(非常)坏的

    非常糟糕的一个:在视图中使用开放会话模式。

    其思想是在生成视图时重新打开entityManager并重新附加实体,这样就不会出现延迟初始化异常。在短期内,这种方法会给你一种错误的感觉,认为你的应用程序运行良好。一旦它投入生产,您的数据库中会有许多并发用户和/或越来越多的记录:您就有很大的风险出现真正的大性能问题(内存使用和/或响应时间)

    (这些潜在问题的根本原因是,在开发小数据库时,您不会注意到这个或那个视图正在获取一个包含10个对象的惰性初始化集合…但在生产中,您的小集合将包含10000个对象!!!)

    这些问题将很难解决,因为: -它们将出现在多个视图中 -它们将很难进行单元/负载测试(因为它们位于视图层)

    在我看来,这种方法只能用于小型非关键应用程序,它们永远不会有巨大的负载或大量的数据

    好方法:使用分层架构。

    视图层不要触摸实体管理器。该层从控制器层接收要显示的数据,所有数据都在那里:不需要在这里获取惰性集合

    控制器层有两个角色:

    • 实现您的业务逻辑
    • 管理entityManager生命周期(和事务边界),并提供可由DAO层使用的entityManager
    此外,控制器层必须向视图层提供完整的对象图。完整的对象图意味着,如果视图需要显示来自该集合的数据,视图层将不会接收未初始化的惰性集合

    DAO层

    只需执行查询以获取数据(这就是编写JPA/HQL/SQL查询的地方)。除了使用控制器层提供的entityManager之外,该层不使用entityManager执行任何特殊操作

    DAO层必须提供广泛的查询来获取这个实体,无论有没有惰性集合,以便满足控制器层的所有需求

    分层体系结构方法的主要优点是,您很快就会在开发过程中看到视图的需求,并且能够在需要时调整和优化查询。(也就是说,你需要一个接一个地修复所有的lazy init异常,但它会让你对视图的要求有一个很好的了解)

    我还修改了我的“选择方法”-我将它包含在一个事务中(就像在我的保存方法中),行为发生了变化:比如启用hibernate.autocommit时,连接不会以“空闲”结束
    private static EntityManagerFactory emf;
    private static final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<EntityManager>();  
    
    public static EntityManager getEntityManager() throws HibernateException {
        EntityManager session = (EntityManager) threadLocal.get();
    
        if (session == null || !session.isOpen()) {
            session = (emf != null) ? emf.createEntityManager()
                    : null;
            threadLocal.set(session);
        }
    
        return session;
    }
    
    java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
        at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:491)
        at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:191)
        at     com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.dest    royResource(C3P0PooledConnectionPool.java:470)
        at     com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.ja    va:964)
        at     com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunn    er.java:547)  
    
     <property name="hibernate.connection.release_mode" value="auto" />