hibernate - c3p0 创建的连接数多于配置中指定的连接数

标签 hibernate c3p0

我的应用程序使用 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 block 中显式关闭 session 和 session 工厂。这是我用来创建 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 [managed: 1, unused: 1, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@7b3f1264)

最佳答案

你是说:

I've set the c3p0.max_size property in my hibernate.cfg.xml file for my application to 50, but the number of JDBC connections created has been exceeding that value.

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

 configuration.buildSessionFactory(serviceRegistry);

并且在该方法中您还关闭了sessionFactory。创建和关闭 sessionFactory 实例都是极其昂贵的操作(您可以看到关闭方法 here )。

最重要的是,当您的应用程序在多个线程中一次处理多个请求时,每个线程都会创建自己的 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.getSessionFactory(),而不是调用 HibernateSessionFactory.create()

关于hibernate - c3p0 创建的连接数多于配置中指定的连接数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13747467/

相关文章:

mysql - 如何从表中删除行而不从引用表中删除行?

MySql - 客户端超时

java - 找不到 org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider 提供程序类

java - Maven 没有解决 hibernate-c3p0 对 slf4j 的依赖

java - 使用jsp从数据库检索数据(Hibernate + Spring + Maven)

java - 不为特定列更改创建修订

java - native 查询 INSERT 给出错误 : Method is only allowed for a Query

java - OneToMany 上的重复条目

spring - 使用 Spring、Hibernate 和 C3P0 管理 Multi-Tenancy Web 应用程序中的连接池

java - c3p0 网络中断后重新连接