我的应用程序使用的是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.所以我想弄清楚为什么这些数字之间存在差异。
[环境:DEVL] [] - 2012-12-06 12:14:07 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@7f1d11b9 [managed: 1,未使用:1,排除:0](例如 com.mchange.v2.c3p0.impl.NewPooledConnection@7b3f1264)
答案 0 :(得分:7)
你这么说:
我已将我的应用程序的hibernate.cfg.xml文件中的c3p0.max_size属性设置为50,但创建的JDBC连接数已超过该值。
这是因为您在insert
方法中调用了create()
方法。每次使用create()
方法,您都会构建一个全新的sessionFactory:
configuration.buildSessionFactory(serviceRegistry);
在该方法中,您还可以关闭sessionFactory
。创建和关闭sessionFactory实例都是极其昂贵的操作(您可以看到结束方法here)。
最重要的是,当您的应用程序在多个线程中一次处理多个请求时,每个线程都会创建自己的sessionFactory(每个都创建自己的池)。因此,在您的系统中存在多个sessionFactory和Connection池。虽然您应该在应用程序的生命周期内只创建一次。因此,当存在多个池副本时,所有池的连接总数可能超过您为一个池配置的最大限制。
我建议你像下面那样改写你的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()
。
答案 1 :(得分:0)
问题是我在我的应用程序中多次创建一个新的会话工厂,而我只需要在应用程序启动时调用它一次。我最终创建了一个实现ServletContextListener接口的类,该接口创建了一个新的会话工厂,并在上下文被销毁时销毁/关闭它。