programing

스프링 부트 시 Postgres 연결이 닫혔습니다.

css3 2023. 3. 1. 11:22

스프링 부트 시 Postgres 연결이 닫혔습니다.

저는 Spring Boot 앱을 실행하여 REST apis를 만들고 있습니다.데이터베이스 접속이 종료되어 그 후 어플리케이션에 콜을 발신할 수 없다는 에러가 자주 발생합니다.Postgres DB를 사용하고 있습니다.스택 트레이스 전체를 다음에 나타냅니다.

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

애플리케이션을 재기동하면, 없어집니다.postgres DB를 재시작할 때 이 문제가 발생하는 것 같습니다.왜 이런 일이 생기는 건가요?

이것은 다른 투고들에 의해 반쪽짜리 답변이고 나는 매우 명확하게 말하고 싶었다.그리고 나는 스프링 부츠 에스크가 되고 싶었다.필요에 따라서, 시간 간격을 자유롭게 변경해 주세요.

옵션 1:에서 끊어진 연결을 버립니다.

다음 속성을 사용합니다.

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

옵션 2: 풀의 연결을 활성 상태로 유지합니다.

다음 속성을 사용합니다.

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

옵션 3: 아이돌 접속을 프로 액티브하게 폐기합니다.

이러한 속성을 사용합니다(주의:이 스프링 부트에 관한 신뢰할 수 있는 문서를 찾을 수 없었습니다.또, 타임 아웃은 밀리초가 아니고 초단위가 됩니다).

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

해피부팅!

매우 타당한 질문이고 이 문제는 보통 많은 사람들이 직면합니다.일반적으로 풀과 데이터베이스 간의 네트워크 연결이 끊어졌을 때(대부분 재시작으로 인해) 예외가 발생합니다., 하고 있는 합니다.jdbc pool접속할 수 있습니다. JDBC pool에는 다양한 연결 풀 설정을 미세 조정하고 풀 내에서 일어나는 일에 대한 세부 정보를 기록하는 옵션이 있습니다.

구성에 대한 자세한 Apache 문서를 참조하여 포기 시간 초과를 지정할 수 있습니다.

removeAbandoned, removeAbandonedTimeout, logAbandoned 파라미터를 확인합니다.

또한 추가 속성을 사용하여 검증을 더욱 강화할 수 있습니다.

test XXX 및 검증 사용연결 유효성을 쿼리합니다.

이 셋업에서도 Tomcat의 DataSource를 사용하는 것과 같은 문제가 있었습니다.(org.apache.tomcat.jdbc.poolHeroku Postgres 결 hero hero :

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.

이 문제를 해결한 것은 DataSource 초기 코드에 이것을 추가하는 것이었습니다(Grails 질문에서 차용).

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

이 세 가지가 모두 안정적인 접속을 위해 필요한지는 잘 모르겠습니다만, 모두 유효하게 해도 큰 문제는 없을 것입니다.

JavaDocs는 무슨 일이 일어나고 있는지 명확히 하고 있습니다.예를 들어, 디폴트로는 이러한 테스트가 이루어지지 않는 것은 조금 의외일 수 있습니다.

이 예외는 기본적으로 JDBC 연결이 닫혔음을 나타내지만 데이터베이스 서버가 실행되고 있지 않음을 의미하지는 않습니다(다른 예외가 있습니다).이 문제는 DB 서버가 재시작되거나 DB 서버가 연결을 끊은 후(예: 시간 초과) 발생할 수 있습니다.여기서의 문제는, 애플리케이션이 새로운 HTTP 요구로 서버에 재접속하지 않는 이유입니다.

통상, 이것은 접속 풀의 잘못된 설정이며, 애플리케이션이 접속을 「빌릴」 때마다 접속을 검증할 필요가 있습니다.이 문제를 해결하기 위해 필요한 것은 다음과 같습니다.

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

기타 설정 파라미터(다른 응답으로부터의)는 이 예외에는 엄밀하게 필요하지 않은 최적화입니다.

다만, JDBC 풀이 적절히 설정되어 있어도, HTTP 요구가 종료한 후에 애플리케이션이 DB 접속을 JDBC 풀로 되돌리지 않고 유지하는 애플리케이션 버그가 발생할 수 있습니다.따라서 JDBC 풀은 DB 연결을 검증할 수도 없습니다(DB 연결이 "ALLOCATED"라는 것만 알고 있습니다).여기서 일반적인 해결책은 응용 프로그램이 연결을 반환하고 각 HTTP 요청에서 새 연결을 "빌리는" 것입니다.

이러한 버그의 예를 다음에 나타냅니다.

@Component
public MyService {
    @Resource
    private EntityManagerFactory emf;
    
    private EntityManager em;
    
    public MyService() {
         em = emf.createEntityManager();//em never return back its JDBC connection to the pool (using em.close())
    }
}

위의 버그에 대한 해결책은 주입/관리된EntityManager를 사용하는 것입니다(권장).

@Component
public MyService {
    @PersistenceContext
    private EntityManager em;
}

직접 관리해야 할 경우 HTTP 요청마다 EntityManager를 생성하여 try-finally 블록으로 닫습니다.

@Component
public MyService {
    @Resource
    private EntityManagerFactory emf;
    
    private EntityManager em;
    
    public void myMethod() {
         EntityManager em = emf.createEntityManager();
         try {
         
         } finaly {
            em.close();//do not forget other cleanup operations like rolling back the transaction
         }
    }
}

저도 똑같은 문제가 있었지만, 제 경우에는 앞서 언급한 답변이 도움이 되지 않았습니다.긴 쿼리를 실행해도 동일한 오류가 발생한다는 것을 알게 되었습니다.제 경우 findAll(Itable ids)에 전화를 걸어 100,000개 이상의 ID 목록을 전달했습니다.목록을 분할하고(예를 들어 Apache Commons 또는 Google Guava의 ListUtils 사용), 더 적은 ID로 findAll()을 호출하면 성공했습니다.

저장소에 쿼리를 쓸 때 저장소에 @Repository 주석을 저장하도록 하십시오.

언급URL : https://stackoverflow.com/questions/29620265/postgres-connection-has-been-closed-error-in-spring-boot