基础知识 - Hibernate / JDBC连接池问题疑难解答

时间:2010-11-05 15:18:46

标签: java hibernate jdbc connection-pooling

Hibernate对从底层连接池获取的数据库连接负有什么责任。是否在使用之前测试连接是否已关闭?如果是这样从池中获得另一个连接?

我在下面提供了错误和确认信息。任何我可以开始解决这个问题的想法都会非常有帮助。以及我们正在使用的SQL Server驱动程序设置的任何建议。

来自Catalina日志的

04-Nov-2010 21:54:52.691 WARNING org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[ConnectionID:8]:java.lang.Exception
    at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:926)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:681)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:545)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:166)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:106)

来自我们的应用程序日志:

2010-11-04 21:54:52,705 [tomcat-http--18] WARN  util.JDBCExceptionReporter  - SQL Error: 0, SQLState: 08S01
2010-11-04 21:54:52,707 [tomcat-http--18] ERROR util.JDBCExceptionReporter  - Socket closed
2010-11-04 21:54:52,708 [tomcat-http--18] ERROR transaction.JDBCTransaction  - JDBC rollback failed
java.sql.SQLException: Connection has already been closed.
    at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:112)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94)
    at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:71)
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94)
    at org.apache.tomcat.jdbc.pool.interceptor.ConnectionState.invoke(ConnectionState.java:132)
    at $Proxy38.rollback(Unknown Source)
    at org.hibernate.transaction.JDBCTransaction.rollbackAndResetAutoCommit(JDBCTransaction.java:217)
    at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:196)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:676)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)

配置

<Resource defaultAutoCommit="false" defaultReadOnly="false"
        defaultTransactionIsolation="SERIALIZABLE"
        driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        fairQueue="false" initialSize="10"
        jdbcInterceptors="ConnectionState;StatementFinalizer"
        jmxEnabled="true" logAbandoned="true" maxActive="100"
        maxIdle="10" maxWait="30000"
        minEvictableIdleTimeMillis="10000" minIdle="10"
        name="com.ourcompany.ap.shoppingcart/datasource"
        password="somePassword" removeAbandoned="true"
        removeAbandonedTimeout="60" testOnBorrow="true"
        testOnReturn="false" testWhileIdle="false"
        timeBetweenEvictionRunsMillis="5000"
        type="javax.sql.DataSource"
        url="jdbc:sqlserver://approd\approd;databaseName=prod"
        useEquals="false" username="AccessPointNet"
        validationInterval="30000" validationQuery="SELECT 1"/>`

6 个答案:

答案 0 :(得分:17)

我有类似的问题,可以通过将 removeAbandonedTimeout 值增加到更高的数字来解决。我们遇到的问题是由于查询花费了更长的时间,上面提到的超时。

答案 1 :(得分:14)

  

Hibernate对从底层连接池获取的数据库连接负有什么责任。

并不多,在Session关闭时释放它。

  

在使用连接之前是否测试连接是否已关闭?如果是这样从池中获得另一个连接?

不,Hibernate没有,如果你愿意,检查连接的有效性是连接池的责任。

  

我在下面提供了错误和确认信息。任何我可以开始解决这个问题的想法都会非常有帮助。

您正在运行什么样的流程?长期交易?它超时了吗? Caused by: 说什么?关于追踪:

2010-11-04 21:54:52,705 [tomcat-http--18] WARN util.JDBCExceptionReporter - SQL Error: 0, SQLState: 08S01 
2010-11-04 21:54:52,707 [tomcat-http--18] ERROR util.JDBCExceptionReporter - Socket closed
2010-11-04 21:54:52,708 [tomcat-http--18] ERROR transaction.JDBCTransaction - JDBC rollback failed java.sql.SQLException: Connection has already been closed.

你能以确定的方式重现它吗?有网络问题吗?

  

关于我们正在使用的SQL Server驱动程序设置的任何建议。

我在下面添加了一个关于Tomcat和连接池配置的优秀资源。但不是特定于SQL Server。

资源

答案 2 :(得分:2)

我们通常使用dbcp解决这个问题,并在定义数据源时提供validationQuery。然后,dbcp将通过发出该查询来验证池连接的可用性(并在将它们返回到应用程序之前透明地重新创建连接,如果它不再有效)。

退房     http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html 了解更多详情。

答案 3 :(得分:2)

我目前在我的项目中使用liquibase(v1.9),当changeSets针对空白模式运行时,它总是花费超过60秒,这导致线程被标记为放弃我不会因为增加removeAbandonedTimeout值,但这是我能够找到的唯一可以解决此问题的解决方案;但是,在初始模式填充完成后,这很少出现问题所以我将值设置回60秒。

答案 4 :(得分:1)

我过去曾处理过一个问题,我们没有正确地将连接返回池中。因此,当使用连接而不返回连接时,在超时时进行数据库调用会引发异常。

我们能够通过调用数据库来重现该问题,等待8小时(postgres的默认超时)并尝试再次调用数据库。它每次抛出相同的异常。我们的解决方案是重新思考(或者更好的是,添加)连接管理策略。

因此,总而言之,您是否通过关闭会话实际上将您的连接返回到池?

答案 5 :(得分:0)

我得到了上述异常的解决方案。 关闭会话时,只需关闭会话工厂的实例。

请查看以下代码:

public class HibernateUtil {
    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
        }
        catch (Throwable ex) {
            ex.printStackTrace();
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionfactory() {
        return sessionFactory;
    }

    public static Session getSession() {
        Session session=sessionFactory.openSession();
        session.getTransaction().begin();
        return session;
    }
    public static void closeSession(Session session) {
        if(session!=null )
        {
            if(session.getTransaction().isActive())
            {
                session.getTransaction().commit();
            }
                session.close();
                getSessionfactory().close();
        }
    }
}

只需调用方法 HibernateUtil.closeSession()。这将解决问题。