在我的应用程序中,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)没有。因此,它尝试查询数据库但没有成功。对我来说还有一点奇怪的是,超时时间变化很大。也许规则特别奇怪或防火墙无法正常工作。无论如何,我无法访问该机器,我只能等待解释。 :(
答案 0 :(得分:7)
我之前遇到过这样的问题,当数据库处于一个单独的盒子上时,其间有一个防火墙设置为超时空闲连接。
在某些情况下,防火墙会以JDBC端未检测到的方式切断连接,并且尝试使用它会导致无限期阻塞。
在我的情况下,它是一个自定义连接池,它在从池中返回之前向连接发送测试查询。我将此测试查询配置为具有超时(使用Statement.setQueryTimeout),以便它不会无限期地阻塞。
答案 1 :(得分:1)
检查池实施的配置。通常情况下,每个连接关闭后都会Apache DBCP为a timeout。
在您的代码中,您不应该保持联系。得到一个,使用它,立即关闭它。游泳池将确保这不会花费太多。
答案 2 :(得分:1)
解决空闲超时问题的一种方法是使用双连接池,一个处于活动状态,另一个处于备用状态(尚未创建连接)。定时器的触发时间远小于FIREWALL_IDLE_TIMEOUT,并在连接池之间切换。我试过这个和ITS工作。
答案 3 :(得分:1)
您必须在DataSource中添加一些参数:
更重要的是添加testOnBorrow和validationQuery
答案 4 :(得分:1)
我们解决了类似症状的问题,这些问题也是由防火墙引起的。
我们能够通过更改testWhileIdle连接池属性来解决此问题,该属性可防止连接空闲以及防火墙关闭连接。见Apache commons dbcp BasicDataSource。这是一个来自配置文件的exert,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