简体   繁体   中英

Spring 3 MVC Hibernate 3.5.4 hibernateTemplate not closing connections (non-transactional)

We are using Spring MVC 3.0.5.RELEASE with Hibernate 3.5.4-Final without transactions. Every time we access the database through the hibernateTemplate it creates a new connection and seemingly never closes them.

UPDATE: we've set maxActive and maxIdle to 5. The application will hang when it tries to open the 6th connection. We allow 100 mysql connections.

Our hibernateTemplate is Autowired, so we're not directly managing these connections. Any ideas on how to make sure these connections are closed?

Here's our spring configuration for hibernate:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName">
        <value>${jdbc.driverClassName}</value>
    </property>
    <property name="url">
        <value>${jdbc.url}</value>
    </property>
    <property name="username">
        <value>${jdbc.username}</value>
    </property>
    <property name="password">
        <value>${jdbc.password}</value>
    </property>
    <property name="maxActive">
        <value>5</value>
    </property>
    <property name="maxIdle">
        <value>5</value>
    </property>
    <property name="removeAbandoned">
        <value>true</value>
    </property>
    <property name="removeAbandonedTimeout">
        <value>30</value>
    </property>
</bean>

<alias name="dataSource" alias="userInfoDataSource"/>

<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource">
        <ref local="dataSource"/>
    </property>
    <property name="packagesToScan" value="com.domain"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.connection.release_mode">after_statement</prop>
            <prop key="hibernate.transaction.flush_before_completion">true</prop>                
        </props>
    </property>
</bean>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Here is our HibernateRepository implementation:

package com.dataAccess.impl;

import org.hibernate.criterion.DetachedCriteria;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public abstract class HibernateRepositoryImpl<T> implements com.dataAccess.Repository<T> {

  @Autowired
  protected HibernateTemplate hibernateTemplate;

  public List<T> find(String query) {
    return hibernateTemplate.find(query);
  }

  @Override
  public void saveOrUpdate(T ENTITY) {
    hibernateTemplate.saveOrUpdate(ENTITY);
  }

  @Override
  public List<T> find(DetachedCriteria criteria) {
    return hibernateTemplate.findByCriteria(criteria);
  }

  @Override
  public void delete(T ENTITY) {
    hibernateTemplate.delete(ENTITY);
  }
}

Here is an example of our we are using it, which seems to leak connections:

package com.dataAccess.impl;

import com.domain.Trigger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class TriggerRepository extends HibernateRepositoryImpl<Trigger> {
  public List<Trigger> getActiveTriggers(Integer patientId) {
    DetachedCriteria findActiveTriggers = DetachedCriteria.forClass(Trigger.class).add(
        Restrictions.and(
            Restrictions.eq("patientId", patientId),
            Restrictions.eq("active", true)
        )
    );
    return super.find(findActiveTriggers);
  }
  public List<Trigger> getInActiveTriggers(Integer patientId) {
    DetachedCriteria findActiveTriggers = DetachedCriteria.forClass(Trigger.class).add(
        Restrictions.and(
            Restrictions.eq("patientId", patientId),
            Restrictions.eq("active", false)
        )
    );
    return super.find(findActiveTriggers);
  }

  public Trigger get(Integer triggerId) {
    return hibernateTemplate.get(Trigger.class, triggerId);
  }
}

The problem ended up being some legacy code which called was chaining several methods together, where the method in the middle of creating the connection -- so the connection was never getting assigned (tough to spot) nor was it ever getting closed. This code was indirectly getting loaded and I wrongly suspected my Hibernate/Spring configuration to be at fault.

If you hit similar issues be wary of lines of code that read:

connectionManager.getConnection().prepareStatement(..).<whatever>

The getConnection() call likely opens a new connection and it nor the prepared statement every have a change to get closed.

I believe that if you aren't using a transactionManager then you should be closing the Hibernate session after each of the operations in your HibernateRepositoryImpl class.

What you have would probably be considered a bug in most situations - you are opening new Hibernate sessions, but they are never being closed - the only reason why you are seeing the SQL statements actually executed against the database is because you have the hibernate.transaction.flush_before_completion property set to true.

Also please make sure that you are not creating more than one instance of HibernateTemplate , i

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml");
Object o=context.getBean("hibernateTemplate");

The object o has to be cached somewhere and returned when your app code is asking for instance of hibernatetemplate .

Thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM