1. 程式人生 > >mysql No operations allowed after connection closed連線異常的解決

mysql No operations allowed after connection closed連線異常的解決

Spring Boot多資料來源配置及No operations allowed after connection closed連線異常的解決

最近專案上線,遇到了一個詭異的bug。

首先說下我的專案配置: SpringBooot + SpringMVC+SpringData JPA+ 兩個MySql

也就是我這個專案配置了多資料來源。

前期開發是沒什麼問題的,一切運轉良好。

但是等到專案上線測試時,經常第二天測試人員就過來報告專案掛掉了。

經過檢視日誌才發現下面這個異常:

2018-01-27 08:09:15,361 - Servlet.service() for servlet [dispatcherServlet] in
context with path [/shop] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: com.mysql.jdbc.exceptions.jdbc
4.MySQLNonTransientConnectionException: No operations allowed after connection closed.] with root cause java.net.SocketException: 斷開的管道 (Write failed)......

注意排查異常要抓住重點: No operations allowed after connection closed。

從這個地方我們知道是mysql的連結關閉了已經。訪問一個關閉了的連結當然會出現異常了。

原因:

之所以會出現這個異常,是因為MySQL5.0以後針對超長時間DB連線做了一個處理,那就是如果一個DB連線在無任何操作情況下過了8個小時後(Mysql 伺服器預設的“wait_timeout”是8小時),Mysql會自動把這個連線關閉。這就是問題的所在,在連線池中的connections如果空閒超過8小時,mysql將其斷開,而連線池自己並不知道該connection已經失效,如果這時有 Client請求connection,連線池將該失效的Connection提供給Client,將會造成上面的異常。
所以配置datasource時需要配置相應的連線池引數,定是去檢查連線的有效性,定時清理無效的連線。

那解決方法是什麼呢?

在application.properties的兩個資料來源的配置下新增如下連線池配置:

#以下為連線池的相關引數配置
spring.datasource.primary.max-idle=10
spring.datasource.primary.max-wait=10000
spring.datasource.primary.min-idle=5
spring.datasource.primary.initial-size=5
spring.datasource.primary.validation-query=SELECT 1
spring.datasource.primary.test-on-borrow=false
spring.datasource.primary.test-while-idle=true
spring.datasource.primary.time-between-eviction-runs-millis=18800
#以下為連線池的相關引數配置
spring.datasource.secondary.max-idle=10
spring.datasource.secondary.max-wait=10000
spring.datasource.secondary.min-idle=5
spring.datasource.secondary.initial-size=5
spring.datasource.secondary.validation-query=SELECT 1
spring.datasource.secondary.test-on-borrow=false
spring.datasource.secondary.test-while-idle=true
spring.datasource.secondary.time-between-eviction-runs-millis=18800

之前也說了因為我是兩個資料來源,所以配置了兩次。當然如果你只有一個數據源,配置一個就可以了。

這樣上述異常就得到解決,其實出現該問題的原因,還是自己本人當時忽略了連線池的相關配置,以及對一些常見連線池的配置尚有欠缺,這裡再補充一個小知識點,spring boot預設會優先使用的連線池是tomcat連線池,前提是在tomcat連線池可用的情況下