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則不檢測池里連接的可用性,

於是假如連接池中的連接被數據庫關閉了,應用通過連接池getConnection時,都可能獲取到這些不可用的連接,且這些連接如果不被其他線程回收的話,它們不會被連接池被廢除,也不會重新被創建,占用了連接池的名額,項目本身作為服務端,數據庫鏈接被關閉,客戶端調用服務端就會出現大量的timeout,客戶端設置了超時時間,然而主動斷開,服務端必然出現close_wait ,由於tomcat 默認最大線程數是200,很快就掛掉,雖說多數源,沒有問題的數據源,鏈接並發過來也會死掉,所以說加大tomcat 默認線程(server.tomcat.max-threads=3000)只是短時間內其他數據源鏈接不會死掉。


默認的配置不適用所有場景,所以使用的時候需要配合場景使用。

由於testOnborrow =true 很大的消耗性能,為了保證服務器的穩定,可以配合其他配置來避免這一點,配合testWhileIdle=true(但是默認為false) 和timeBetweenEvictionRunsMillis來避免這種問題,所以設置testOnborrow =false是可以提高效率的


原文:https://blog.csdn.net/qq_38023253/article/details/80815618


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM