我的spring + hibernate应用程序不会关闭jdbc连接

时间:2014-05-05 19:20:05

标签: mysql spring hibernate tomcat jdbc

我在生产中有Spring + Hibernate + Tomcat + MySql应用程序,我遇到了问题。我认为应用程序没有关闭它的jdbc连接,当它达到其限制(当前为200)时,应用程序停止响应,我必须重新启动tomcat。我需要在某处关闭此连接吗?这是我的数据源:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/" override="true" reloadable="false" swallowOutput="false">
    <!-- jdbcInterceptors, removeAbandoned, removeAbandonedTimeout van juntos, ver http://www.tomcatexpert.com/blog/2012/01/24/using-tomcat-7-jdbc-\
    connection-pool-production, y https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html -->
    <!-- removeAbandonedTimeout es en segundos -->

    <Resource name="jdbc/catWDB" auth="Container" type="javax.sql.DataSource"
              driverClassName="com.mysql.jdbc.Driver"
              factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
              url="@URL@"
              username="@USERNAME@"
              password="@PASSWORD@"

              maxActive="200"
              maxIdle="50"
              minIdle="10"
              suspectTimeout="60"
              timeBetweenEvictionRunsMillis="30000"
              minEvictableIdleTimeMillis="60000"

              validationQuery="select 1"
              validationInterval="30000"
              testOnBorrow="true"

              removeAbandoned="true"
              removeAbandonedTimeout="60"
              abandonWhenPercentageFull="10"
              maxWait="10000"

              jdbcInterceptors="ResetAbandonedTimer;StatementFinalizer"


            />

</Context>

这是appdynamics监控连接的图片,从3天到现在

app Dynamics image

以下是catalina.out日志文件中出现的错误摘录:

  

输入例外报告

     

消息请求处理失败;嵌套异常是   org.hibernate.exception.JDBCConnectionException:无法打开   连接

     

description 服务器遇到内部错误,无法完成此请求。

     

例外

     

org.springframework.web.util.NestedServletException:Request   处理失败;嵌套异常是   org.hibernate.exception.JDBCConnectionException:无法打开   连接   org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:932)   org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:816)   javax.servlet.http包。 。 。

     

根本原因

     

org.hibernate.exception.JDBCConnectionException:无法打开   连接   org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:99)   org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)   org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)   org.hibernate.jdbc.ConnectionManager。 。 。

     

根本原因

     

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:    连接太多   sun.reflect.GeneratedConstructorAccessor67.newInstance(Unknown Source)   sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)   java.lang.reflect.Constructor.newInstance(Constructor.java:513)   com.mysql.jdbc.Util.handleNewInstance(Util.java:406)   com.mysql.jdbc.Util.getInstance(Util.java:381)   com.mysql.jdbc.SQLError。

更新

public Category findByIdByApp(Integer id, int appListId) throws DataAccessException {

       Criteria criteria = getSession().createCriteria(Category.class,"category")
                .createAlias("appList", "app")
                .add(Restrictions.and(Restrictions.eq("category.categoryId", id), Restrictions.eq("app.appListId", appListId)));
          List result=criteria.list();

        if(result.size()==1)

                return (Category) result.get(0);
         else
                return null;
    }

类别域对象的映射方式如下:

@Entity
@Table(name = "category")
public class Category implements Comparable, Serializable {

所以我的猜测是,考虑到mithridas评论,我手动使用hibernate会话,我需要用这样的东西关闭它们:

this.getSession().clear();

或者我可以实现@PersistenceContext。 有人会指导我这个实现,所以我可以评估哪个最适合我们使用?

谢谢。

UPDATE2: 添加了更多信息以回答James Massey评论:

这些是我的:datasource,sessionFactory,transactionManager和categoryDAO sessionFactory赋值:

<!-- ========================= DATA ACCESS OBJECT DEFINITIONS ======================== -->

<bean id="dataSource"
      class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName">
        <value>java:comp/env/jdbc/catWDB</value>
    </property>
</bean>


<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref local="dataSource"/>
    </property>
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />

    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.connection.pool_size">3</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.max_fetch_depth">1</prop>

        </props>
    </property>
</bean>


<!---->
<bean id="transactionManager" lazy-init="true"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
        <ref local="sessionFactory"/>
    </property>

</bean>



<bean id="categoryDAOTarget" class="com.bamboo.catW3.DAO.impl.CategoryDAOImpl">
    <property name="sessionFactory">
        <ref local="sessionFactory"/>
    </property>
</bean>

2 个答案:

答案 0 :(得分:3)

问题不在于会话,而是在连接池中,正确管理的会话,但JDBC层中的连接池没有关闭连接。

这些是我为修复它们所做的事情。

JDBC上下文配置

1.-将JDBC连接工厂从tomcat的旧BasicDataSourceFactory更改为tomcat的新DataSourceFactory

2.-根据本文调整JDBC设置: http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency

会话工厂xml配置

3.-从会话工厂配置中删除此行:

<prop key="hibernate.max_fetch_depth">1</prop>

这是我的配置结束的方式:

JDBC上下文配置

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/" override="true" reloadable="false" swallowOutput="false">
    <Resource name="jdbc/catWDB" auth="Container" type="javax.sql.DataSource"
              driverClassName="com.mysql.jdbc.Driver"
              factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
              url="@URL@"
              username="@USERNAME@"
              password="@PASSWORD@"
              maxActive="200"
              maxIdle="50"
              minIdle="10"
              suspectTimeout="60"
              timeBetweenEvictionRunsMillis="30000"
              minEvictableIdleTimeMillis="60000"
              validationQuery="select 1"
              validationInterval="30000"
              testOnBorrow="true"
              removeAbandoned="true"
              removeAbandonedTimeout="60"
              abandonWhenPercentageFull="10"
              maxWait="10000"
              jdbcInterceptors="ResetAbandonedTimer;StatementFinalizer"
            />
</Context>

会话工厂xml配置

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
            </props>
        </property>
</bean>

答案 1 :(得分:1)

我认为您应该使用@PersistenceContext注释从Spring上下文获取EntityManager并使用@Transactional注释来驱动您的事务。这样您就不必担心手动关闭Hibernate会话,并且在连接太多之前,连接数不会增加。