【问题标题】:Connection hangs after time of inactivity不活动时间后连接挂起
【发布时间】:2010-12-25 17:25:15
【问题描述】:

在我的应用程序中,Spring 管理用于数据库访问的连接池。 Hibernate 使用这些连接进行查询。乍一看,我对池没有任何问题:它可以在并发客户端和只有一个连接的池中正常工作。我可以执行很多查询,所以我认为我(或 Spring)不会留下打开的连接。

我的问题出现在一段时间不活动后(有时 30 分钟,有时超过 2 小时)。然后,当 Hibernate 进行一些搜索时,它会持续太多。将 log4j 级别设置为 TRACE,我得到以下日志:

...
18:27:01 DEBUG nsactionSynchronizationManager  - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@99abd7] for key [org.hibernate.impl.SessionFactoryImpl@7d2897] bound to thread [http-8080-Processor24]
18:27:01 DEBUG HibernateTransactionManager     - Found thread-bound Session [org.hibernate.impl.SessionImpl@8878cd] for Hibernate transaction
18:27:01 DEBUG HibernateTransactionManager     - Using transaction object [org.springframework.orm.hibernate3.HibernateTransactionManager$HibernateTransactionObject@1b2ffee]
18:27:01 DEBUG HibernateTransactionManager     - Creating new transaction with name [com.acjoventut.service.GenericManager.findByExample]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
18:27:01 DEBUG HibernateTransactionManager     - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@8878cd]
18:27:01 TRACE SessionImpl                     - setting flush mode to: AUTO
18:27:01 DEBUG JDBCTransaction                 - begin
18:27:01 DEBUG ConnectionManager               - opening JDBC connection

在这里它会被冻结大约 2 到 10 分钟。但接着继续:

18:30:11 DEBUG JDBCTransaction                 - current autocommit status: true
18:30:11 DEBUG JDBCTransaction                 - disabling autocommit
18:30:11 TRACE JDBCContext                     - after transaction begin
18:30:11 DEBUG HibernateTransactionManager     - Exposing Hibernate transaction as JDBC transaction [jdbc:oracle:thin:@212.31.39.50:30998:orcl, UserName=DEVELOP, Oracle JDBC driver]
18:30:11 DEBUG nsactionSynchronizationManager  - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@843a9d] for key [org.apache.commons.dbcp.BasicDataSource@7745fd] to thread [http-8080-Processor24]
18:30:11 DEBUG nsactionSynchronizationManager  - Initializing transaction synchronization
...

之后,它可以正常工作,直到另一段不活动。恕我直言,似乎连接池返回了一个无效/关闭的连接,当 Hibernate 意识到这一点时,请求另一个连接池。

我不知道如何解决这个问题或我可以做些什么来划定它。实现这一目标的任何帮助将不胜感激。

谢谢。

编辑:嗯,最后是由于防火墙规则。数据库检测到连接丢失,但池(dbcp 或 c3p0)没有。因此,它尝试查询数据库但没有成功。对我来说仍然很奇怪的是超时时间是非常可变的。也许规则特别奇怪或防火墙无法正常工作。无论如何,我无法访问那台机器,我只能等待解释。 :(

【问题讨论】:

  • 您如何确定这是否是防火墙问题?我面临着一个类似的问题,即 dbcp 在我的 Spring Batch 事务中无限期挂起并且永远不会返回

标签: java oracle hibernate spring jdbc


【解决方案1】:

我们解决了具有类似症状的问题,这也是由防火墙引起的。

我们可以通过更改 testWhileIdle 连接池属性来解决此问题,该属性可防止连接空闲并防止防火墙关闭连接。见Apache commons dbcp BasicDataSource。以下是解决问题的配置文件persistentce-context.xml 中的一个尝试:

<property name="testWhileIdle">
  <value>true</value>
</property>
<property name="minEvictableIdleTimeMillis">
  <value>600000</value>
</property>
<property name="timeBetweenEvictionRunsMillis">
  <value>600000</value>
</property>

很可能我们只需要添加 testWhileIdle(默认为 false),但添加了其他两个属性以更好地衡量。

在我们的例子中,这里是我们看到的一些日志。请注意,在此调试日志中,打开连接需要 16 分钟才能使用连接,这就是导致一切挂起的原因。没有导致难以追踪的错误。

09-06-13 @ 16:36:34 [DEBUG] HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@db17ab]
09-06-13 @ 16:36:34 [DEBUG] ConnectionManager - opening JDBC connection
09-06-13 @ 16:52:00 [DEBUG] DataSourceUtils - Setting JDBC Connection
09-06-13 @ 16:52:00 [DEBUG] JDBCTransaction - begin
09-06-13 @ 16:52:00 [DEBUG] JDBCTransaction - current autocommit status: true

【讨论】:

    【解决方案2】:

    您必须在数据源中添加一些参数:

    更重要的添加 testOnBorrow 和 validationQuery

    【讨论】:

      【解决方案3】:

      解决空闲超时问题的一种方法是使用双连接池,一个处于活动状态,另一个处于待机状态(尚未创建连接)。有一个触发时间远小于 FIREWALL_IDLE_TIMEOUT 的计时器,并在连接池之间切换。我试过了,它的工作原理。

      【讨论】:

        【解决方案4】:

        我之前遇到过这样的问题,当数据库在一个单独的盒子上并且中间有防火墙设置为超时空闲连接时。

        在某些情况下,防火墙会以 JDBC 端无法检测到的方式切断连接,并且尝试使用它会导致无限期阻塞。

        在我的例子中,它是一个自定义连接池,它在从池中返回之前向连接发送一个测试查询。我将此测试查询配置为超时(使用 Statement.setQueryTimeout),这样它就不会无限期地阻塞。

        【讨论】:

        • 我不确定您为什么要使用自定义池来仅发送测试查询。有点像样的连接池和/或容器管理的数据源已经能够做到这一点。例如 DBCP 和 Tomcat JNDI 也是如此。请参考配置文档,在每个关键字下使用 validationQuery
        • 这是在一个项目中(很久很久以前),它使用了一个定制的连接池,并且在确实与 DBCP 中的validationQuery 做类似事情的代码部分中。
        • 你是对的。似乎问题出在我无法控制的某些防火墙规则上。我认为最好的解决方案是改变防火墙行为。谢谢。
        【解决方案5】:

        检查您的池实施的配置。通常是Apache DBCP,每个连接在关闭后都有a timeout

        在您的代码中,您不应该保持连接。得到一个,使用它,立即关闭它。游泳池将确保这不会花费太多。

        【讨论】:

        • Spring 管理我的连接,所以我不是必须明确调用 Connection.close() 的人。我是吗?正如你所说,我正在使用 org.apache.commons.dbcp.BasicDataSource,并带有 destroy-method="close"。我会研究一下。
        • 还有两个其他问题来源: 您和数据库服务器之间可能有防火墙(但是空闲 TCP 连接的 2 小时超时有点短)。或者您的数据库配置为在一段时间后关闭空闲连接。请参阅 DBCP 的其他配置选项以检查死连接并定期 ping DB 以保持管道打开。
        • 至于关闭:不,您不应该关闭它,但您应该结束事务(这将使 Spring 看到可以将连接返回到池中)。
        猜你喜欢
        • 1970-01-01
        • 2015-02-01
        • 1970-01-01
        • 2018-12-02
        • 1970-01-01
        • 2013-08-18
        • 2018-10-13
        • 2015-07-20
        相关资源
        最近更新 更多