Spring Boot环境下出现No operations allowed after connection close错误

一个基于springcloud的微服务项目,详细配置: SpringCloud + SpringMVC+SpringData JPA+ MySql+Postgresql

其中项目配置了多数据源,前期开发测试是没什么问题的,但是等到项目在服务器上面测试时,第二天就上午出现了数据库连接异常。经过查看日志发现下面这个异常:


注意异常信息: No operations allowed after connection closed

也就是说jpa获取的连接是已经关闭的了,对一个关闭了的链接进行操作导致出现异常了。

原因:

之所以会出现这个异常,是因为MySQL5.0以后针对超长时间DB连接做了一个处理,那就是如果一个DB连接在无任何操作情况下过了8个小时后(Mysql 服务器默认的“wait_timeout”是8小时),Mysql会自动把这个连接关闭。这就是问题的所在,在连接池中的connections如果空闲超过8小时,mysql将其断开,而连接池自己并不知道该connection已经失效,如果这时有 Client请求connection,连接池将该失效的Connection提供给Client,将会造成上面的异常。 
所以配置datasource时需要配置相应的连接池参数,定是去检查连接的有效性,定时清理无效的连接。

解决方法

在application.yml的两个数据源的配置下添加如下连接池配置(红色字体部分):

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
server:
  port: 9013
spring:
  application:
    name: api
  datasource:
    druid:
      #数据库连接1
      mysql:
        name: mysql
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/datacube?useUnicode=true&characterEncoding=utf8&useSSL=false
        username: root
        password: rootrot
      #数据库连接2
      greenplum:
        name: greenplum
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.postgresql.Driver
        url: jdbc:postgresql://localhost:5432/datacube?useUnicode=true&characterEncoding=utf8&useSSL=false
        username: root
        password: rootroot


    # 下面为连接池的补充设置,应用到上面所有数据源中
    # 初始化大小,最小,最大
      initialSize: 5
      minIdle: 10
      maxActive: 1000
      #配置获取连接等待超时的时间
      maxWait: 60000
      #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      #配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      #验证连接是否有效。此参数必须设置为非空字符串,下面三项设置成true才能生效
      validationQuery: SELECT 1
      #指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
      testWhileIdle: true
      #指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
      testOnBorrow: true
      #指明是否在归还到池中前进行检验
      testOnReturn: false
      #打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      filters: stat,wall,log4j
      #通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=1000;druid.stat.logSlowSql=true
      #合并多个DruidDataSource的监控数据
      useGlobalDataSourceStat: true
#      WebStatFilter:
#        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
#      stat-view-servlet:
#       login-username: admin
#       login-password: admin


jpa:
   database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
   show-sql: true
   hibernate:
     #dialect: org.hibernate.dialect.MySQL5Dialect
     ddl-auto: none
     naming:
      strategy: org.hibernate.cfg.ImprovedNamingStrategy


在这个项目中使用的是阿里的druid连接池,配置简单,除了数据库地址,驱动类,用户名和密码其他一起都是默认,开始的时候由于项目更新上线频率比较多,没有出现太多的问题,后来换库了 。导致之前的链接失效了,请求的时候时好时坏,跟了一下代码以及其他项目的配置,其中有一个属性 testOnBorrow设置为false(默认设置为false) ,testOnBorrow=false则不检测池里连接的可用性,

扫描二维码关注公众号,回复: 2256138 查看本文章

于是假如连接池中的连接被数据库关闭了,应用通过连接池getConnection时,都可能获取到这些不可用的连接,且这些连接如果不被其他线程回收的话,它们不会被连接池被废除,也不会重新被创建,占用了连接池的名额,项目本身作为服务端,数据库链接被关闭,客户端调用服务端就会出现大量的timeout,客户端设置了超时时间,然而主动断开,服务端必然出现close_wait ,由于tomcat 默认最大线程数是200,很快就挂掉,虽说多数源,没有问题的数据源,链接并发过来也会死掉,所以说加大tomcat 默认线程(server.tomcat.max-threads=3000)只是短时间内其他数据源链接不会死掉。

默认的配置不适用所有场景,所以使用的时候需要配合场景使用。

由于testOnborrow =true 很大的消耗性能,为了保证服务器的稳定,可以配合其他配置来避免这一点,配合testWhileIdle=true(但是默认为false) 和timeBetweenEvictionRunsMillis来避免这种问题,所以设置testOnborrow =false是可以提高效率的


参考链接1

参考链接2

参考链接3



猜你喜欢

转载自blog.csdn.net/qq_38023253/article/details/80815618