救救小妹吧,ssh為什么每次連數據庫都新建sessionFactory和connection?


情況描述:ssh下,我有一個定時發送郵件的模塊,每次都要連接數據庫,按照Hibernate的介紹,sessionFactory只初始化一次,連接池中的connection可重用,但是為什么我的每次都重新新建sessionFactory,connection也不斷開,數據庫中的連接不斷增多,tomcat占着內存不放,最終導致outOfMemory。
配置文件如下:<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>${datasource.driverClassName}</value>
</property>
<property name="url">
<value>${datasource.url}</value>
</property>
<property name="username">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
<property name="maxActive">
<value>${datasource.maxActive}</value>
</property>
<property name="maxWait">
<value>${datasource.maxWait}</value>
</property>
<property name="defaultAutoCommit">
<value>${datasource.defaultAutoCommit}</value>
</property>
<property name="defaultReadOnly">
<value>${datasource.defaultReadOnly}</value>
</property>
</bean>
<bean id="SessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.connection.release_mode">
${hibernate.connection.release_mode}
</prop>
</props>
</property>
<property name="mappingResources">
。。。。。。。。。。。。。。。
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="SessionFactory" />
</property>
</bean>
<bean id="baseTxProxy" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
配置文件有些長,但是這個問題己經煩了我很久了,迫不得己麻煩大家,希望各位大蝦們幫幫忙看一下吧,在這里先謝謝了!

9 个解决方案

#1


把<prop key="hibernate.connection.release_mode">${hibernate.connection.release_mode}</prop>去掉試試

#2


wangzhouyu(小小) 謝謝你的關注!

以前是沒有加這個屬性的,但查找大量資料后發現了有一個自動釋放連接的參數,我就加了,${hibernate.connection.release_mode的值我設的是after_transaction 事務完成后就自動釋放連接。雖然不設的話,默認是auto,hibernate自己根據情況設置,但是也沒用。

還有,我這是用的dbcp的連接池,我本來是想用c3po的,因為看文檔說hibernate推薦c3po,但是我用它的時候,服務器啟動后就不停地在配置文件打這個出來:
Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@20f237 [ connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@1716fa0 [ acquireIncrement -> 5, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, idleConnectionTestPeriod -> -1, initialPoolSize -> 15, maxIdleTime -> 10, maxPoolSize -> 1000, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 10, nestedDataSource -> com.mchange.v2.c3p0.DriverManagerDataSource@18b1f8f [ description -> null, driverClass -> com.microsoft.sqlserver.jdbc.SQLServerDriver, factoryClassLocation -> null, jdbcUrl -> jdbc:sqlserver://localhost:2869;instanceName=SQL2005;databasename=survey, properties -> {user=******, password=******} ] , preferredTestQuery -> null, propertyCycle -> 300, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, usesTraditionalReflectiveProxies -> false ] , factoryClassLocation -> null, numHelperThreads -> 3, poolOwnerIdentityToken -> 20f237 ] ............
很多很多,不停地初始化,我也不知道是為什么。

#3


按照Hibernate的介紹,sessionFactory只初始化一次,連接池中的connection可重用,但是為什么我的每次都重新新建sessionFactory

這個沒有錯的,你的每個dao執行的時候都是new了一個新的sessionFactory。所以不停的連接。

我一般是建立一個HibernateListener,在工程啟動的時候,連接 建立sessionFactory。

以后每個dao就不需要重新連接了。這樣就是啟動建立sessionFactory的時候速度慢,但是使用dao就快了,因為不需要重新連接。

#4


HibernateListener :
public class HibernateListener implements ServletContextListener {

    private static Logger log = Logger.getLogger(HibernateListener.class);

    
    public void contextInitialized(ServletContextEvent event) {
        log.info("Starting Hibernate persistence service...");
        HibernateSessionFactory.currentSession(); // Just call static initializer
        log.info("Hibernate startup complete");
    }

    public void contextDestroyed(ServletContextEvent event) {
        log.info("Shutting down Hibernate persistence service...");
        HibernateSessionFactory.closeSession();
        log.info("Hibernate shutdown complete");
    }
}

web.xml:

   <listener>
<listener-class>com.test.common.hibernate.HibernateListener</listener-class>
   </listener>

DAO:
        Session session = currentSession();   //HibernateSessionFactory.currentSession();   不需要每次新建立連接HibernateSessionFactory了
        Transaction t = session.beginTransaction();

#5


很感謝SDMRauquin(冷月無心) ,不管是否可以,我還是會試一下你的方案的!
但實際上我並沒有在DAO里重新建SessionFactory,我的DAO里是
Session session = this.getSession();

而且我現在在測試的時候僅僅只是用了Hibernate自帶的hql語句和HibernateTemplate,並沒有用到JDBC自己建連接:
Session session = this.getSession();
Connection conn = session.connection();
比如說獲得所有要發的郵件:
public List getAllMailTask() {

try {return (List) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
Query query = session.createQuery("FROM MailTask ");
List list=query.list();
        return list;
}
}
);}catch(Exception e){
e.printStackTrace();
return null;
}
}

#6


SDMRauquin(冷月無心)  還有就是我想問一下,如果你自己初始化sessionFactory的話,Spring就不會管你的session了,我看你的HibernateListener中有contextDestroyed()關閉session的,是不是你在每個事務提交后都需要手動關閉session,也就是調用contextDestroyed()呢。

#7


我用spring的話,我也是用c3po的

在beam.xml:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>WEB-INF/classes/hibernate.cfg.xml</value> //就是單獨使用hibernate的配置
</property> 

<!-- 為處理Blob類型字段的句柄聲明-->
<property name="lobHandler" ref="lobHandler"/>

</bean>

<!-- DaoTraget>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-->
<bean id="expoPurchTopicDaoTarget" class="org.caexpo.hibernate.dao.impl.ExpoPurchTopicDAO">
<property name="sessionFactory">
  <ref bean="sessionFactory"/>
</property>
</bean>

#8


DAO: 
... ...
        Session session = currentSession();
        Transaction t = session.beginTransaction();
... ...
        session.save(expert);
        session.flush();         
        t.commit();        
        closeSession();   //HibernateSessionFactory.closeSession()
... ...

contextDestroyed並不是在一個dao結束的時候調用的.

contextInitialized和contextDestroyed是根據服務的啟動而啟動或者關閉的

#9


經過一天的debug,終於發現了問題,是我自己無意中又初始化了sessionFactory
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {GlobalVar.APPCONETN_URL});
GlobalVar.APPCONETN_URL =WEB-INF/ApplicationContext.xml

我把它放在定時發送郵件的函數中,所以每隔一段時間都會新建連接(池),呵呵!

但是我又出現了一個問題,我需要獲得ApplicationContext.xml中己經注冊了的bean,我在另一個類中定義一個靜類變量來接收它的值。

我用了 獲得spring里注冊Bean的方法:http://blog.chinajavaworld.com/entry.jspa?id=500
的第二種,但是獲得的
在 UserService userService = (UserService)service.getService("userService");返回的userService 是null,為什么我不能用呢。可以幫忙看看嗎?謝謝

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com