web-dev-qa-db-fra.com

La connexion Postgres a été fermée erreur dans Spring Boot

J'exécute une application Spring Boot pour créer REST apis. J'obtiens souvent un message d'erreur indiquant que la connexion à la base de données est fermée et, par la suite, je ne peux plus appeler de l'application. J'utilise Postgres DB. C'est la trace complète de la pile:

org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed: 
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.Java:431)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.Java:373)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.Java:457)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.Java:276)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207)
    at com.Sun.proxy.$Proxy91.findByUriMoniker(Unknown Source)
    at com.mypkg.businessobjects.OrderInfoBO.getOrderInfo(OrderInfoBO.Java:76)
    at com.mypkg.controller.OrderInfoController.getOrderInfo(OrderInfoController.Java:78)
    at Sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.lang.reflect.Method.invoke(Method.Java:483)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.Java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.Java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.Java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.Java:777)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.Java:706)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.Java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:966)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.Java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.Java:687)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.Java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.Java:790)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.Java:85)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.Java:130)
    at com.mypkg.config.CORSFilter.doFilter(CORSFilter.Java:39)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.Java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.Java:132)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.Java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.Java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.Java:132)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.Java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.Java:61)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.Java:36)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.Java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.Java:56)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.Java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.Java:45)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.Java:63)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.Java:58)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.Java:70)
    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.Java:76)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.Java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.Java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.Java:261)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.Java:247)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.Java:76)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.Java:166)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.Java:197)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.Java:759)
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
    at Java.lang.Thread.run(Thread.Java:745)
Caused by: javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed: 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.Java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.Java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.Java:1771)
    at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.Java:64)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.Java:159)
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.Java:380)
    ... 56 more
Caused by: org.hibernate.TransactionException: JDBC begin transaction failed: 
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.Java:76)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.Java:162)
    at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.Java:1435)
    at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.Java:61)
    ... 58 more
Caused by: org.postgresql.util.PSQLException: This connection has been closed.
    at org.postgresql.jdbc2.AbstractJdbc2Connection.checkClosed(AbstractJdbc2Connection.Java:833)
    at org.postgresql.jdbc2.AbstractJdbc2Connection.getAutoCommit(AbstractJdbc2Connection.Java:794)
    at Sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.lang.reflect.Method.invoke(Method.Java:483)
    at org.Apache.Tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.Java:126)
    at org.Apache.Tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.Java:108)
    at org.Apache.Tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.Java:81)
    at com.Sun.proxy.$Proxy56.getAutoCommit(Unknown Source)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.Java:68)
    ... 61 more

Lorsque je redémarre l'application, elle disparaît. Je pense que ce problème se produit lorsque je redémarre ma base de données postgres. Pourquoi cela arrive-t-il?

20
drunkenfist

Question très valable et ce problème est généralement confronté par beaucoup. L'exception se produit généralement lorsque la connexion réseau est perdue entre le pool et la base de données (la plupart du temps à cause d'un redémarrage). En regardant la trace de la pile que vous avez spécifiée, il est clair que vous utilisez jdbc pool pour établir la connexion. JDBC pool a des options pour affiner divers paramètres de pool de connexions et consigner des détails sur ce qui se passe dans le pool.

Vous pouvez vous référer à à la documentation détaillée Apache sur la configuration du pool pour spécifier le délai d'abandon

Recherchez les paramètres removeAbandoned, removeAbandonedTimeout, logAbandoned

De plus, vous pouvez utiliser des propriétés supplémentaires pour resserrer davantage la validation.

Utilisez testXXX et validationQuery pour la validité de la connexion.

10
CuriousMind

C'est un peu à moitié répondu par les autres posts et je voulais être très explicite. Aussi je voulais être plus Spring-Boot-esque. N'hésitez pas à modifier les intervalles de temps si nécessaire.

Option 1: Supprimez les connexions rompues de la piscine.

Utilisez ces propriétés:

spring.datasource.test-on-borrow=true
spring.datasource.validation-query=SELECT 1;
spring.datasource.validation-interval=30000

Option 2: Maintenir les connexions dans la piscine en vie.

Utilisez ces propriétés:

spring.datasource.test-while-idle=true
spring.datasource.validation-query=SELECT 1;
spring.datasource.time-between-eviction-runs-millis=60000

Option 3: Lancer de manière proactive les connexions inactives.

Utilisez ces propriétés (Remarque: je n’étais pas en mesure de trouver une documentation fiable sur celui-ci pour Spring Boot. Le délai d’expiration est également en secondes et non en millisecondes):

spring.datasource.remove-abandoned=true
spring.datasource.remove-abandoned-timeout=60

Bon démarrage!

22
James Watkins

J'ai eu exactement le même problème, avec cette configuration , en utilisant également DataSource de Tomcat (org.Apache.Tomcat.jdbc.pool) pour se connecter à Heroku Postgres:

org.springframework.transaction.CannotCreateTransactionException: 
    Could not open JPA EntityManager for transaction
org.hibernate.TransactionException: JDBC begin transaction failed: ] 
    with root cause
org.postgresql.util.PSQLException: This connection has been closed.

Ce qui a résolu le problème pour moi, c’est d’ajouter cela au code init de DataSource (emprunt de une question Grails ):

dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
dataSource.setTestOnReturn(true);
dataSource.setValidationQuery("SELECT 1");

Je ne sais pas si ces trois éléments sont nécessaires pour obtenir une connexion stable - peut-être pas -, mais avoir tous les droits activés ne fait probablement pas beaucoup de mal.

Les JavaDocs clarifient ce qui se passe: voir par exemple setTestOnBorrow() . Un peu surprenant, peut-être, qu’aucun test de ce type n’est effectué par défaut. 

1
Jonik

J'ai eu exactement le même problème mais dans mon cas, les réponses susmentionnées n'ont pas aidé. J'ai compris que lorsque vous faites une longue requête, la même erreur apparaît. Dans mon cas, j'ai appelé findAll (identifiants Iterable) et transmis une liste énorme de plus de 100 000 identifiants. Le partitionnement de la liste (par exemple, en utilisant ListUtils à partir d’Apache Commons ou de Google Guava) et l’appel de findAll () avec moins d’id (id) ont été décisifs.

0
Tai Truong