当前位置: 首页 > 知识库问答 >
问题:

如何修复圣杯中的连接池泄漏?

须原
2023-03-14

这就是Grails 2.4.4。我遇到了一个连接池泄漏,似乎与Grails事务管理有关。有人知道问题在哪里吗?

来自Tomcat JDBC池的可疑泄漏检测消息:

015-06-11 13:44:03,483 [PoolCleaner[2120388162:1434055276957]] [||] WARN  pool.ConnectionPool  - Connection has been marked suspect, possibly abandoned PooledConnection[org.postgresql.jdbc4.Jdbc4Connection@4fcf9353][89657 ms.]:java.lang.Exception
at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:1063)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:780)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:619)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:188)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:128)
at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.getTargetConnection(LazyConnectionDataSourceProxy.java:403)
at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.invoke(LazyConnectionDataSourceProxy.java:376)
at com.sun.proxy.$Proxy77.prepareStatement(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
at com.sun.proxy.$Proxy77.prepareStatement(Unknown Source)
at groovy.sql.Sql$CreatePreparedStatementCommand.execute(Sql.java:4512)
at groovy.sql.Sql$CreatePreparedStatementCommand.execute(Sql.java:4491)
at groovy.sql.Sql.getAbstractStatement(Sql.java:4342)
at groovy.sql.Sql.getPreparedStatement(Sql.java:4357)
at groovy.sql.Sql.getPreparedStatement(Sql.java:4434)
at groovy.sql.Sql.access$900(Sql.java:228)
at groovy.sql.Sql$PreparedQueryCommand.runQuery(Sql.java:4622)
at groovy.sql.Sql$AbstractQueryCommand.execute(Sql.java:4553)
at groovy.sql.Sql.rows(Sql.java:1954)
at groovy.sql.Sql.firstRow(Sql.java:2192)
at groovy.sql.Sql$firstRow.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
...

在resources.groovy中:

import groovy.sql.Sql
beans = {
    sql(Sql, ref("dataSource"));
}

在DataSource.groovy中:

dataSource {
url = "jdbc:postgresql:testdb"
username = "USERNAME"
password = "PASSWORD"
driverClassName = "org.postgresql.Driver"
dialect = "org.hibernate.dialect.PostgreSQL9Dialect"
pooled = true
jmxEnabled = true
readOnly = false
autoCommit = false
properties {
    initialSize = 1
    maxActive = 15
    minIdle = 1
    maxIdle = 2
    maxWait = 20000 // 20 seconds
    maxAge = 20 * 60000 // 20 minutes
    timeBetweenEvictionRunsMillis = 15000
    minEvictableIdleTimeMillis = 10000
    validationQueryTimeout = 10 // 10 seconds
    validationInterval = 15000 // 15 seconds
    testOnBorrow = true
    testWhileIdle = true
    testOnReturn = false
    logValidationErrors = true
    removeAbandonedTimeout = 60 * 1440 // 24 hours, use suspectTimeout instead
    removeAbandoned = true // needed for suspectTimeout
    suspectTimeout = 60
    logAbandoned = true // needed for suspectTimeout logging
    validationQuery = "SELECT 1"
}
}

TestController.groovy:

class TestController {
  def testService

  def test() {
    Integer id = testService.test()
    render "Testing: $id\n"
  }
}  

TestService.groovy:

import grails.transaction.Transactional

@Transactional
class TestService {
    def sql

    @Transactional
    Integer test() {
        def row = sql.firstRow("select id from TestTable where name = 'Test'")
        return row.id
    }
}

泄漏检测消息不显示查询是否从事务性服务移动到控制器,我假设这是因为控制器不是事务性的。

如果我在 resources.groovy 中更改为使用数据源的未代理版本,它也不会报告泄漏消息:

import groovy.sql.Sql
beans = {
    sql(Sql, ref("dataSourceUnproxied"));
}

深入挖掘实际的groovy.sql。对于Sql代码,在我看来,问题与firstRow()使用try{}finally{块从池中打开和关闭自己的连接有关。但它获得的连接是通过Spring TransactionWareConnectionFactoryProxy代理的。

在代理源代码中,我看到:

else if (method.getName().equals("close")) {
    // Handle close method: only close if not within a transaction.                             
    ConnectionFactoryUtils.doReleaseConnection(this.target, this.connectionFactory);
    return null;
}

好的,那么如果在事务中,底层连接不会被释放回池?这对我来说没有什么意义,因为它总是在@Transactional service方法中的事务中,所以连接永远不会关闭,除非Grails或Spring中的其他地方有代码在提交()之后关闭()连接?

共有1个答案

潘辰龙
2023-03-14

想出来了。

我在 resources.groovy 中配置了一个 JmsTransactionManager

事实证明,我还需要显式添加JDBC事务管理器。我必须向resources.groovy添加以下内容:

transactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager, ref("dataSource"))

这给了我一个带有Grails的ChainedTransactionManager,其中包含JmsTransactionManagerDataSourceTransactionManager

我没有使用Hibernate。如果使用Hibernate/GORM,而不是DataSourceTransactionManager,您将需要org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager

 类似资料:
  • 我有一个带有数据库连接池的grails/groovy web应用程序。设置如下所示: 我使用java melody进行诊断和监控,并注意到一些奇怪的行为。例如,当执行查询数据库的作业时,连接可以超越maxActive属性。为什么这是可能的? 我需要显式关闭Grails连接吗?该作业调用一个服务方法,该方法通过withCriteria Grails调用简单地执行DB查询,如: 似乎每次运行这个程序,

  • 在为了使用多线程而修改了一个服务方法之后,我发现如果不止一个用户多次尝试请求页面(并调用服务方法),服务器就会抛出“无法连接,池耗尽”异常。让我提供一个我的服务类的例子。 我已经在这个问题上挣扎了一个多星期,我找不到解决方案。我不太明白Grails如何与会话、连接和事务一起工作。我的猜测是跟随。当调用ConvertDocumentToJSON时,它从池中获取连接(4个用户,每个用户25个线程=10

  • 我上面代码的日志是: 数据库也会更新。为什么lock()不工作?不是在lock()之后其他实例无法更新吗?还是别的什么?还是我错过了什么?

  • 我正在尝试识别应用程序中的SQL连接泄漏。经过一些操作后,当我的应用程序处于空闲状态(用户未执行任何活动)时,我在返回的结果集中看到7个与我的数据库的连接。所有连接的状态均为,所有连接的值均为。 我正在使用连接池,但连接字符串中未指定连接生存期。这意味着如果我是对的,将使用它的默认值0。连接生存期的值为零意味着SQL server永远不应该关闭连接,对吗? 我让我的应用程序空闲一段时间(15-20

  • 本文向大家介绍CSS 使用Flexbox的圣杯布局,包括了CSS 使用Flexbox的圣杯布局的使用技巧和注意事项,需要的朋友参考一下 示例 Holy Grail布局是具有固定高度的页眉和页脚以及中心带有3列的布局。这3列包括一个固定宽度的sidenav,一个流体中心以及一个用于其他内容(例如广告)的列(流体中心在标记中排在最前面)。CSS Flexbox可以通过非常简单的标记来实现此目的: HT

  • 我们使用spring数据中的Oracle AQ支持在同一数据源上同时使用JMS和JDBC,使用本地事务而不是XA。我们的设置基本上是参考手册中所描述的:在orcl上:aq jms连接工厂:使用本地数据源事务=“true”和本机jdbc提取器=“oracleNativeJdbcExtractor”HibernateTransactionManager(我现在正尝试对aq和Hibernate使用单一数