我的 spring+hibernate 应用程序没有关闭 jdbc 连接

Posted

技术标签:

【中文标题】我的 spring+hibernate 应用程序没有关闭 jdbc 连接【英文标题】:My spring+hibernate app does not closes jdbc connections 【发布时间】:2014-06-22 04:55:48 【问题描述】:

我在生产中有一个 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>

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

这是我在 catalina.out 日志文件中遇到的错误的摘录:

输入异常报告

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

说明服务器遇到内部错误,导致它无法完成此请求。

例外

org.springframework.web.util.NestedServletException: 请求 处理失败;嵌套异常是 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(未知来源) 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;
    

Category 域对象映射如下:

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

所以我的猜测是,考虑到 mithridas cmets,我正在手动使用休眠会话,我需要用这样的方式关闭它们:

this.getSession().clear();

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

谢谢。

更新 2: 在回答 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>

【问题讨论】:

如何打开/关闭 Hibernate 会话?您是使用 @PersistenceContext 从 Spring 获取 EntityManager 还是手动打开/关闭 Hibernate 会话?如果您手动打开 Hibernate 会话,则需要自己关闭它。 我不确定,因为应用程序那部分的原始设计者离开了,我认为我们在 AOP 配置中使用了这个类来处理它: org.springframework.transaction.interceptor.TransactionProxyFactoryBean ,但我不知道如何检查你的要求。你能帮我吗?谢谢。 查看是否有Hibernate的Session对象手动使用,如Session sess = factory.openSession(); 谢谢你mithridas,你的评论很有用,我根据你的评论更新了问题,因为它的信息太多了。 您能否发布您的会话工厂和事务管理器配置。或者你没有使用 Spring 的 Session Factory 和 Transaction Manager?不使用这些对象的缺陷是手动管理会话很困难,并且容易出现您所描述的问题。如果您正在使用这些对象,则说明您的配置有问题。 【参考方案1】:

问题不在于会话,而在于连接池,会话被正确管理,但 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>

【讨论】:

您的 jdbc 连接与 server.xml 文件中的服务器连接相比如何 - 尝试比较 jdbc 与服务器连接的比率以比较指标。【参考方案2】:

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

【讨论】:

谢谢你mithridas,我会用这篇文章试试你的建议:studytrails.com/frameworks/spring/spring-hibernate-jpa.jsp,并在生产测试后回来。 您好,我添加了您的建议,但事实证明问题不在会话中,而是在连接池中,会话被正确管理,但 jdbc 层中的连接池不是关闭连接。

以上是关于我的 spring+hibernate 应用程序没有关闭 jdbc 连接的主要内容,如果未能解决你的问题,请参考以下文章

spring3.0整合异常,我的框架为struts2.1+hibernate3.0+spring3.0+mysql5.0+tomcat6.0

我的 spring+hibernate 应用程序没有关闭 jdbc 连接

spring + hibernate - 将实体映射到不同的数据源

Spring + Hibernate 框架

spring / hibernate - 按当前用户 ID 过滤

Spring + Hibernate + Spring Security 配置