首次發佈問題。謝謝大家!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