2012-12-06 115 views
2

我的應用程序使用Hibernate 4.1.7和c3p0 0.9.1。c3p0創建比配置中指定的更多連接

我已將我的應用程序的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月6日12時14分07秒DEBUG BasicResourcePool:1644 - 跟蹤[email protected] [管理: 1,未使用的: 1,排除:0](如 [email protected]

回答

0

問題是我在應用程序內多次創建一個新的會話工廠,而我只需要在應用程序啓動時調用它。我最終創建了一個實現了ServletContextListener接口的類,該接口創建了一個新的會話工廠,並在銷燬上下文時銷燬/關閉它。

+1

這就是我在我的答案中所描述的......:P –

7

您是說:

我已經設置在c3p0.max_size財產我的hibernate.cfg.xml文件爲我的應用程序增加到50,但是JDBC的conn數量創造的創造力已經超過了這個價值。

發生這種情況是因爲在您調用create()方法的insert方法中。在create()方法每一次,你建立一個全新的SessionFactory的是這樣的:

configuration.buildSessionFactory(serviceRegistry); 

,並在該方法中,你也關閉sessionFactory。創建和關閉sessionFactory實例都是非常昂貴的操作(您可以看到關閉方法here)。最重要的是,當您的應用程序在多個線程中同時處理多個請求時,每個線程都會創建自己的sessionFactory(每個線程創建自己的池)。所以一次有幾個sessionFactory和連接池存在於你的系統中。雖然您應該在應用程序的整個生命週期中只創建一次。因此,當存在多個池副本時,所有池的連接總數可能會超過最大限制,因此您爲一個池進行了配置。

我建議你重寫你的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()

+0

我添加了該屬性,將其設置爲30秒,並刪除了idleTime。但是,當數據庫中的JDBC連接數量增加時,它們不會縮小,而是留下一堆INACTIVE數據庫。我不明白爲什麼游泳池會在有空閒遊泳池時繼續創建更多連接。 – Brian

+0

根據文檔,我認爲c3p0.timeout與c3p0.maxIdleTime屬性相同。 – Brian

+0

連接數是否超過您的最大池大小? –