Springboot应用程序在数据库重启时失败

时间:2018-10-31 06:00:16

标签: java spring-boot

我们已经开发了Springboot Java应用程序,并将其放在用于开发环境的docker容器中。

Spring引导版本为1.5.6

使用的数据库是SQL Server 2016,它再次位于docker(Windows容器)上。

问题: 每当我重新启动SQL DB容器时,应用程序就会开始显示此错误。

2018-10-29 16:00:08,993 ERROR pool-13-thread-1  org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task.
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.
        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:447)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy155.findOne(Unknown Source)
        at au.com.outware.swepad.tasks.WorkOrderManagerTask.taskFetchAndProcessWorkOrderDetails(WorkOrderManagerTask.java:63)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
        at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
        at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.PersistenceException: com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1700)
        at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:48)
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:189)
        at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380)
        ... 30 common frames omitted
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.
        at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:206)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.checkClosed(SQLServerConnection.java:724)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.setAutoCommit(SQLServerConnection.java:2615)
        at sun.reflect.GeneratedMethodAccessor163.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        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.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:79)
        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.$Proxy102.setAutoCommit(Unknown Source)
        at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.begin(AbstractLogicalConnectionImplementor.java:67)
        at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:238)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214)
        at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52)
        at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1512)
        at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:45)
        ... 32 common frames omitted
2018-10-29 16:00:08,995 WARN pool-30-thread-1  org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: null
2018-10-29 16:00:08,996 ERROR pool-30-thread-1  org.hibernate.engine.jdbc.spi.SqlExceptionHelper - The connection is closed.
2018-10-29 16:30:00,017 INFO pool-13-threa

使应用程序正常工作的唯一方法是重新启动应用程序(容器重新启动)

我们在论坛上进行了搜索,并在我们的application.yml中设置了此属性。

spring.datasource.tomcat.testOnBorrow=true
spring.datasource.tomcat.validation-query=SELECT 1

我们的应用yml如下图所示。

spring:
  datasource:
    type: org.apache.tomcat.jdbc.pool.XADataSource
    tomcat:
      test-on-borrow: true
      validation-query: select 1
      validation-interval: 30000
  jpa:
    database: sql_server
    database-platform: org.hibernate.dialect.SQLServer2012Dialect
    generate-ddl: false
    hibernate:
      ddl-auto: none

我们在yml文件中确实有一个单独的部分,用于开发,登台,产品环境。

我们正在将dev配置文件用于开发环境。是否要求我们在本节中放置tomcat属性?

---
spring:
  profiles: dev,staging,prod
  datasource:
    url: "jdbc:sqlserver://${DB_IP}:${DB_PORT};databaseName=${DB_NAME}"
    username: "${DB_USER}"
    password: "${DB_PASS}"
    initialize: false
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none

任何想法都可以解决此问题。

谢谢。

3 个答案:

答案 0 :(得分:0)

请确保您的数据库正在属性文件(portip-address)中定义的.yaml.properties上运行。

org.springframework.transaction.CannotCreateTransactionException: Could not 
open JPA EntityManager for transaction; nested exception is 
javax.persistence.PersistenceException: com.microsoft.sqlserver.jdbc.SQLServerException: 
The connection is closed.

如果您仔细地看到自己的异常并阅读消息,您将很容易识别问题。

此处堆栈跟踪显示EntityManager无法初始化,因为连接已关闭。

  

注意:请验证您的数据库是否正在运行?

答案 1 :(得分:0)

问题1:连接池配置,用于在可用时自动重新连接

您不清楚使用哪种配置文件以及构造哪种类型的数据源。但是,我将发布此指南参考。

  

使用哪种类型的数据源使您可以使用属性   特定于此。

我引用Spring Boot doc(https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database)-

  
      
  • 我们更喜欢HikariCP的性能和并发性。如果HikariCP可用,我们总是选择它。
  •   
  • 否则,如果Tomcat池数据源可用,我们将使用它。
  •   
  • 如果HikariCP和Tomcat池数据源均不可用,并且Commons DBCP2不可用,我们将使用它。
  •   
     

如果您使用spring-boot-starter-jdbc或   spring-boot-starter-data-jpa“入门”,您会自动获得一个   对 HikariCP 的依赖。

因此,除非您明确要求使用Tomcat连接池(通过spring.datasource.type application.yml 中进行过),否则您将获得HikariCp。因此,请仔细选择。


因此,这些是Tomcat和HikariCP的属性,可以帮助您自动重新连接:

Tomcat JDBC连接池:

spring.datasource.tomcat.testOnBorrow = true
spring.datasource.tomcat.validation-query = SELECT 1

Hikari CP:

#connectionTestQuery not needed for JDBC4 drivers. You can add them unless complained
spring.datasource.hikari.connectionTestQuery = SELECT 1
spring.datasource.hikari.connectionInitSql = SELECT 1

PS::当心您使用的配置文件和数据源类型。您在tomcat中有一个,在dev,qa和prod中都有默认的HikariCp。铭记。 关于数据库的验证查询,请参考此处的文章: https://stackoverflow.com/a/3670000/2931410

问题2:经常断开连接的Docker Windows容器

  • 尝试安装最新的docker版本
  • 如果仍然无法正常运行,请尝试在Docker中切换到Linux容器。

答案 2 :(得分:0)

我们能够找到此问题的解决方案。 问题是这条线
    type: org.apache.tomcat.jdbc.pool.XADataSource
我们将上面的行替换为
type: org.apache.tomcat.jdbc.pool.DataSource

在断开与db的连接之后,现在应用程序无需重新启动即可重新连接到db。

感谢大家的想法。

毗湿奴