首次发布问题。谢谢大家!Tomcat 8连接已被放弃
我遇到的问题已经有一段时间了,我们找不到解决方案。总之,使用Java 8,Spring,Hibernate,PostgreSQL,JSF(PrimeFaces这里),Webflow构建应用程序。 有关连接的问题被关闭,但似乎该应用程序仍然使用它,一些逻辑借用它相同的连接,它只是“失蹄”,因此接下来的时间,并抛出异常:
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
Caused by: java.sql.SQLException: Connection has already been closed.
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:117)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108)
应用可以为工作几天没有问题,直到发生什么事,它从哪里得到连接放弃警告从tomcat。从那里,只是不会正常工作,许多过程会拿到关闭的连接,将可测量的失败,因为连接已经关闭:
WARNING [Tomcat JDBC Pool Cleaner[1989780873:1502425160484]] org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[[email protected]]:java.lang.Exception
at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:1093)
我们的团队花费在这个问题上几个小时,在网络搜索,并咨询了开发人员,一开始,他们都试图调整Tomcat server.xml,但没有取得任何成功。它可能会在未来运行良好,然后在服务器不一致的情况下出现同样的问题,因此唯一要做的就是重新启动它。我们添加的拦截器并没有帮助,只是作为解决问题的一部分。
只有后来我们才能可靠地复制这个问题,而且这个问题本身就很有趣。所以,如果在事务,自定义或常规Java内抛出任何异常(例如,如果存在基于断言的NoResultException或某个MyCustomException),则Tomcat会抛出Abandoned Connection(关闭它); 60秒后(removeAbandonedTimeout)Tomcat将显示警告消息并且连接将被关闭。但是逻辑仍然指向它的问题,以及更多的连接关闭了线路,更多的事情在执行业务逻辑时破坏了。
有server.xml中配置了两个数据源(一个用于业务逻辑,另一个用于职位)如下:
<Resource auth="Container" driverClassName="org.postgresql.Driver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
initialSize="5"
jdbcInterceptors=
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx (threshold=10000)"
logAbandoned="true"
maxActive="30"
minEvictableIdleTimeMillis="30000"
minIdle="5"
name="jdbc/my-app-db"
password=""
removeAbandoned="true"
removeAbandonedTimeout="60"
testOnBorrow="true"
testOnReturn="false"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="5000"
type="javax.sql.DataSource"
url="jdbc:postgresql://mydb.rds.amazonaws.com:5432/mydb_db"
username=""
validationInterval="30000"
validationQuery="SELECT 1" />
<Resource auth="Container"
driverClassName="org.postgresql.Driver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
initialSize="5"
jdbcInterceptors=
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;
org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx (threshold=10000)"
logAbandoned="true"
maxActive="30"
minEvictableIdleTimeMillis="30000"
minIdle="5"
name="jdbc/my-app-db-for-jobs"
password=""
removeAbandoned="true"
removeAbandonedTimeout="60"
testOnBorrow="true"
testOnReturn="false"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="5000"
type="javax.sql.DataSource"
url="jdbc:postgresql://mydb.rds.amazonaws.com:5432/myapp_db"
username=""
validationInterval="30000"
validationQuery="SELECT 1" />
和XML配置:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="acme"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"></property>
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
和pom.xml的一些依赖关系:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-faces</artifactId>
<version>2.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.1.1</version>
</dependency>
这里是一段代码可能会失败,但是rea LLY任何有交易,或任何查询DB可以在封闭的池连接如绊倒:
PromoCode promoCodeEntity = null;
try {
JpaTransactionManager transactionManager = (JpaTransactionManager) ApplicationContextProvider
.getApplicationContext().getBean("transactionManager");
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
String jpql = "select p from PromoCode p where p.code = :code";
Query query = em.createQuery(jpql).setParameter("code", promoCode);
promoCodeEntity = (PromoCode) query.getSingleResult();
if (promoCodeEntity.getQuantyOfUses() >= promoCodeEntity.getTotalOfUses()) {
MyCustomException myCustomException = new MyCustomException("This promo code is not valid: [" + promoCode + "]");
MyCustomException.setCode("PROMO_CODE");
throw myCustomException;
}
if (!promoCodeEntity.getActive() || promoCodeEntity.getFinish()) {
MyCustomException myCustomException = new MyCustomException("This promo code is not valid: [" + promoCode + "]");
myCustomException.setCode("PROMO_CODE");
throw myCustomException;
}
if (!(promoCodeEntity.getStartDateValid().before(new Date())
&& promoCodeEntity.getEndDateValid().after(new Date()))) {
MyCustomException myCustomException = new MyCustomException("This promo code is expired: [" + promoCode + "]");
myCustomException.setCode("PROMO_CODE");
throw myCustomException;
}
promoCodeEntity.setQuantyOfUses(promoCodeEntity.getQuantyOfUses() + 1);
transactionManager.commit(status);
} catch (NoResultException e) {
MyCustomException myCustomException = new MyCustomException("Promo code not found: [" + promoCode + "]");
myCustomException.setCode("PROMO_CODE");
throw myCustomException;
}
有没有人遇到这样的问题,或者我应该在哪里看得更远?我们做了一些驱动程序更新(例如postgres jdbc),目前也正在评估c3p0 Pool,以查看这是否与Tomcat Pool错误相关。但真的很高兴能够理解错误。
感谢响应。这个问题与查询花费太长时间无关,可能,但现在不行。我们目前使用HikariCP Pool进行了设置,但问题并没有消失。连接可能已用尽,但由于查询超时原因而不同。 – user3711719