2

我的应用程序使用的是 Hibernate 4.1.7 和 c3p0 0.9.1。

我已将应用程序的 hibernate.cfg.xml 文件中的 c3p0.max_size 属性设置为 50,但创建的 JDBC 连接数已超过该值。此外,我在 Hibernate 配置中也指定了非活动/空闲连接不会被删除。这是我的配置中的一个片段:

<property name="c3p0.acquire_increment">1</property>
<property name="c3p0.autoCommitOnClose">false</property>
<property name="c3p0.max_size">50</property>
<property name="c3p0.min_size">1</property>
<property name="c3p0.numHelperThreads">1</property>
<property name="c3p0.maxIdleTime">30</property> 
<property name="c3p0.maxIdleTimeExcessConnections">20</property>
<property name="c3p0.maxConnectionAge">45</property>

我在代码中的 finally 块中明确关闭了我的会话和会话工厂。这是我用来创建 SessionFactory 实例的类:

package ics.sis.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

import ics.global.runtime.Environment;
import ics.util.properties.PropertiesISUWrapper;

public class HibernateSessionFactory {
    private static SessionFactory sessionFactory;
    private static ServiceRegistry serviceRegistry;
    private static final PropertiesISUWrapper ISU_PROPERTIES = new PropertiesISUWrapper(Environment.getName(),"VzAppIntegration"); 

    public static SessionFactory create() {
        Configuration configuration = new Configuration();
        configuration.configure();

        configuration.setProperty("hibernate.connection.url", ISU_PROPERTIES.getUrl());
        configuration.setProperty("hibernate.connection.password", ISU_PROPERTIES.getPassword());

        serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();        
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        return sessionFactory;
    }

}

这是执行数据库事务的主要方法之一:

public static int insert(int aidm, String termCode, String wappCode) throws SQLException, ClassNotFoundException {      
        // Initialize session and transaction
        SessionFactory sessionFactory = HibernateSessionFactory.create();
        Session session = sessionFactory.openSession();
        Transaction tx = null;
        int applSeqno = 0;
        Stvwapp wapp = null;

        try {
            tx = session.beginTransaction();

            applSeqno = generateApplSeqNo(session, aidm);
            SarheadId sarheadIdDao = new SarheadId();
            sarheadIdDao.setSarheadAidm(aidm);
            sarheadIdDao.setSarheadApplSeqno((short)applSeqno);

            // Find STVWAPP row by WAPP code
            Query query = session.getNamedQuery("findStvwappByWappCode"); 
            query.setString("wappCode", wappCode);

            if (query.list().size() == 0) {
                throw new RuntimeException("Invalid WAPP code specified: " + wappCode);
            } else {
                wapp = (Stvwapp) query.list().get(0);
            }

            Sarhead sarheadDao = new Sarhead();
            sarheadDao.setId(sarheadIdDao);
            sarheadDao.setSarheadActivityDate(new java.sql.Timestamp(System.currentTimeMillis()));
            sarheadDao.setSarheadAddDate(new java.sql.Timestamp(System.currentTimeMillis()));
            sarheadDao.setSarheadAplsCode("WEB");
            sarheadDao.setSarheadApplAcceptInd("N");
            sarheadDao.setSarheadApplCompInd("N");
            sarheadDao.setSarheadApplStatusInd("N");
            sarheadDao.setSarheadPersStatusInd("N");
            sarheadDao.setSarheadProcessInd("N");
            sarheadDao.setSarheadTermCodeEntry(termCode);
            sarheadDao.setStvwapp(wapp);

            session.save(sarheadDao);
        } finally {
            tx.commit();
            session.close();
            sessionFactory.close(); 
        }

        return applSeqno;
    }

更新

我将 c3p0 的日志级别更改为 DEBUG 以获得更详细的连接池日志记录,并且我看到它每 3 或 4 秒检查一次过期连接。此外,我看到正在记录以下行,在我看来,池中总共有两个连接。但是,在 Toad 中,我正在监视打开的 JDBC 连接总数,它显示为 6。所以我试图弄清楚为什么这些数字之间存在差异。

[Env:DEVL] [] - 2012-12-06 12:14:07 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@7f1d11b9 [托管:1,未使用:1,排除:0](例如com.mchange.v2.c3p0.impl.NewPooledConnection@7b3f1264)

4

2 回答 2

8

你是说:

我已将应用程序的 hibernate.cfg.xml 文件中的 c3p0.max_size 属性设置为 50,但创建的 JDBC 连接数已超过该值。

发生这种情况是因为在您的insert方法中您正在调用create()方法。每次在您的create()方法中,您都会像这样构建一个全新的 sessionFactory:

 configuration.buildSessionFactory(serviceRegistry);

并且在该方法中,您还关闭了sessionFactory. 创建和关闭 sessionFactory 实例都是非常昂贵的操作(您可以在此处查看关闭方法)。

最重要的是,当您的应用程序在多个线程中一次处理多个请求时,每个线程都会创建自己的 sessionFactory(每个线程都会创建自己的池)。因此,您的系统中同时存在多个 sessionFactory 和 Connection pool。虽然您应该在应用程序的整个生命周期内只创建一次。因此,当存在多个池副本时,所有池的连接总数可能会超过您为一个池配置的最大限制。

我建议你HibernateSessionFactory像下面这样重写你的课程:

public class HibernateSessionFactory {
    private static SessionFactory sessionFactory = HibernateSessionFactory.create();
    private static ServiceRegistry serviceRegistry;
    private static final PropertiesISUWrapper ISU_PROPERTIES = new PropertiesISUWrapper(Environment.getName(),"VzAppIntegration"); 

    private static SessionFactory create() {
        Configuration configuration = new Configuration();
        configuration.configure();

        configuration.setProperty("hibernate.connection.url", ISU_PROPERTIES.getUrl());
        configuration.setProperty("hibernate.connection.password", ISU_PROPERTIES.getPassword());

        serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();        
        return configuration.buildSessionFactory(serviceRegistry);

    }

    public static SessionFactory getSessionFactory(){
       return sessionFactory;
    }

}

并且在insert()方法中而不是调用HibernateSessionFactory.create(),只需调用HibernateSessionFactory.getSessionFactory()

于 2012-12-06T16:13:39.860 回答
0

问题是我在我的应用程序中多次创建一个新的会话工厂,而我只需要在应用程序启动时调用它一次。我最终创建了一个实现 ServletContextListener 接口的类,该接口创建了一个新的会话工厂并在上下文被销毁时销毁/关闭它。

于 2012-12-06T20:51:47.807 回答