基础 - 解决 Hibernate / JDBC 连接池问题

Posted

技术标签:

【中文标题】基础 - 解决 Hibernate / JDBC 连接池问题【英文标题】:Basics - Troubleshooting Hibernate / JDBC Connection Pool Issue 【发布时间】:2011-05-05 16:05:10 【问题描述】:

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

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

来自 Catalina 日志:

2010 年 11 月 4 日 21:54:52.691 警告 org.apache.tomcat.jdbc.pool.ConnectionPool.abandon 连接已被放弃 PooledConnection[ConnectionID:8]:java.lang.Exception 在 org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:926) 在 org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:681) 在 org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:545) 在 org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:166) 在 org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:106)

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

2010-11-04 21:54:52,705 [tomcat-http--18] WARN util.JDBCExceptionReporter - SQL 错误:0,SQLState:08S01 2010-11-04 21:54:52,707 [tomcat-http--18] 错误 util.JDBCExceptionReporter - 套接字关闭 2010-11-04 21:54:52,708 [tomcat-http--18] 错误 transaction.JDBCTransaction - JDBC 回滚失败 java.sql.SQLException:连接已经关闭。 在 org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:112) 在 org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94) 在 org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:71) 在 org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94) 在 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState.invoke(ConnectionState.java:132) 在 $Proxy38.rollback(未知来源) 在 org.hibernate.transaction.JDBCTransaction.rollbackAndResetAutoCommit(JDBCTransaction.java:217) 在 org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:196) 在 org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:676) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412) 在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 在 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"/>`

【问题讨论】:

【参考方案1】:

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

【讨论】:

你在开玩笑吗?您只是将问题转移到未来更长时间的事件中 刚刚遇到同样的问题。在我的情况下,执行由 Hibernate 创建的 OUTER JOIN(由于具有 EAGERly 加载的“OneToMany”依赖项的实体)结果花费了很多时间(比我的“removeAbandonedTimeout”设置(60)多,并且导致 SQLState : 08S01 错误。看起来 Hibernate 在处理废弃的连接删除时遇到了困难。【参考方案2】:

Hibernate 从底层连接池获得的数据库连接的责任是什么。

不多,当Session关闭时释放它。

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

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

我在下面包含了错误和确认信息。任何关于我可以从哪里开始解决此问题的想法都会非常有帮助。

您正在运行什么样的进程?长期交易?是否超时? Caused by: 说了什么?关于跟踪:

2010-11-04 21:54:52,705 [tomcat-http--18] WARN util.JDBCExceptionReporter - SQL 错误:0,SQLState:08S01 2010-11-04 21:54:52,707 [tomcat-http--18] 错误 util.JDBCExceptionReporter - 套接字关闭 2010-11-04 21:54:52,708 [tomcat-http--18] 错误 transaction.JDBCTransaction - JDBC 回滚失败 java.sql.SQLException:连接已关闭。

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

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

我在下面添加了有关 Tomcat 和连接池配置的精彩资源。虽然不是特定于 SQL Server。

资源

Configuring jdbc-pool for high-concurrency

【讨论】:

原来的链接没了,但是被wayback机器记录下来了:web.archive.org/web/20180521112213/http://www.tomcatexpert.com/…【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

所以,总而言之,您实际上是通过关闭 Session 将连接返回到池中吗?

【讨论】:

当我尝试一次插入许多记录时,我也遇到了这个问题(上传作业,文件由 1,60,000 条记录组成)。 5分钟后我得到了错误。能够在 5 分钟后抛出错误的所有时间重现多次。有人可以帮我吗?【参考方案6】:

我得到了上述异常的解决方案。 在关闭会话的同时也关闭会话工厂的实例。

看下面的代码:

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()。这样就可以解决问题了。

【讨论】:

我不认为这是推荐的:***.com/questions/33236407/…

以上是关于基础 - 解决 Hibernate / JDBC 连接池问题的主要内容,如果未能解决你的问题,请参考以下文章

ORM 解决方案(JPA;Hibernate)与 JDBC

Spring基础4

[Hibernate开发之路]基础配置

Hibernate基础知识

Hibernate基础

hibernate简介