gpt4 book ai didi

grails - 如何修复Grails中的连接池泄漏?

转载 作者:行者123 更新时间:2023-12-02 14:50:48 24 4
gpt4 key购买 nike

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

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

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
}
}

泄漏检测消息不会显示查询是否从事务服务移动到 Controller ,我认为这是因为 Controller 不是事务性的。

如果将resources.groovy更改为使用数据源的未代理版本,它也不会报告泄漏消息:
import groovy.sql.Sql
beans = {
sql(Sql, ref("dataSourceUnproxied"));
}

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

在代理源代码中,我看到:
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服务方法中的事务中,因此除非Grails或Spring中的其他代码在提交后将close()连接,否则连接永远不会关闭。 ()?

最佳答案

弄清楚了。

我在JmsTransactionManager中配置了resources.groovy

事实证明,我还需要显式添加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 - 如何修复Grails中的连接池泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30791565/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com