您好,登錄后才能下訂單哦!
這篇文章主要介紹Spring Boot集成Druid出現異常報錯的原因是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
在Spring Boot集成Druid項目中,發現錯誤日志中頻繁的出現如下錯誤信息:
discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, lastPacketReceivedIdleMillis : 172675
經過排查發現是Druid版本導致的異常,在1.2.2及以前版本并未出現如此異常。而在其以上版本均存在此問題,下面就來分析一下異常原因及解決方案。
首先上面的異常并不影響程序的正常運行,但作為程序員看到程序中不停的出現異常還是難以忍受的。所以還是要刨根問底的解決一下的。
跟蹤堆棧信息會發現對應的異常是從com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal方法中拋出的,對應的代碼如下:
if (valid && isMySql) { // unexcepted branch long lastPacketReceivedTimeMs = MySqlUtils.getLastPacketReceivedTimeMs(conn); if (lastPacketReceivedTimeMs > 0) { long mysqlIdleMillis = currentTimeMillis - lastPacketReceivedTimeMs; if (lastPacketReceivedTimeMs > 0 // && mysqlIdleMillis >= timeBetweenEvictionRunsMillis) { discardConnection(holder); String errorMsg = "discard long time none received connection. " + ", jdbcUrl : " + jdbcUrl + ", jdbcUrl : " + jdbcUrl + ", lastPacketReceivedIdleMillis : " + mysqlIdleMillis; LOG.error(errorMsg); return false; } } }
上述代碼中,MySqlUtils.getLastPacketReceivedTimeMs(conn) 是獲取上一次使用的時間,mysqlIdleMillis 就是計算出來空閑的時間,timeBetweenEvictionRunsMillis 是常量60秒。如果連接空閑了60秒以上,那就discardConnection(holder) 丟棄這個舊連接并順帶打印了一個日志LOG.warn(errorMsg)。
在上述代碼中,我們看到進入該業務邏輯是有前提條件的,也就是valid和isMySql變量同時為true。isMySql為true是必須的,我們使用的本身就是Mysql數據庫。那么是否可以讓valid為false呢?這樣不就不會進入該業務處理了嗎?
來看看valid的來源,還是在該方法的上面:
boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);
我們找到validConnectionChecker的Mysql實現子類MySqlValidConnectionChecker,該類中對isValidConnection的實現如下:
public boolean isValidConnection(Connection conn, String validateQuery, int validationQueryTimeout) throws Exception { if (conn.isClosed()) { return false; } if (usePingMethod) { if (conn instanceof DruidPooledConnection) { conn = ((DruidPooledConnection) conn).getConnection(); } if (conn instanceof ConnectionProxy) { conn = ((ConnectionProxy) conn).getRawObject(); } if (clazz.isAssignableFrom(conn.getClass())) { if (validationQueryTimeout <= 0) { validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT; } try { ping.invoke(conn, true, validationQueryTimeout * 1000); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof SQLException) { throw (SQLException) cause; } throw e; } return true; } } String query = validateQuery; if (validateQuery == null || validateQuery.isEmpty()) { query = DEFAULT_VALIDATION_QUERY; } Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); if (validationQueryTimeout > 0) { stmt.setQueryTimeout(validationQueryTimeout); } rs = stmt.executeQuery(query); return true; } finally { JdbcUtils.close(rs); JdbcUtils.close(stmt); } }
我們可以看到上述方法中有三個返回的地方:第一個連接已關閉;第二個使用ping的形式進行檢查;第三,使用select 1的方式進行檢查。而使用ping的形式檢查時,無論是否拋異常都會返回true。這里我們禁用該模式即可。
進入ping的業務邏輯主要靠變量usePingMethod來判斷,追蹤代碼會發現在這里進行的設置:
public void configFromProperties(Properties properties) { String property = properties.getProperty("druid.mysql.usePingMethod"); if ("true".equals(property)) { setUsePingMethod(true); } else if ("false".equals(property)) { setUsePingMethod(false); } }
那么,也就是說,當我們把系統屬性druid.mysql.usePingMethod設置為false即可禁用該功能。
找到了問題的根源,那么剩下的就是如何禁用了,通常有三種形式。
第一,在啟動程序時在運行參數中增加:-Ddruid.mysql.usePingMethod=false。
第二,在Spring Boot項目中,可在啟動類中添加如下靜態代碼快:
static { System.setProperty("druid.mysql.usePingMethod","false"); }
第三,類文件配置。在項目的DruidConfig類中新增加:
/* * 解決druid 日志報錯:discard long time none received connection:xxx * */ @PostConstruct public void setProperties(){ System.setProperty("druid.mysql.usePingMethod","false"); }
至此,已可以成功關閉該功能,異常信息再也不會出現了。
猜測,阿里給數據庫設置的數據庫空閑等待時間是60秒,mysql數據庫到了空閑等待時間將關閉空閑的連接,以提升數據庫服務器的處理能力。
MySQL的默認空閑等待時間是8小時,就是「wait_timeout」的配置值。如果數據庫主動關閉了空閑的連接,而連接池并不知道,還在使用這個連接,就會產生異常。
springboot一種全新的編程規范,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程,SpringBoot也是一個服務于框架的框架,服務范圍是簡化配置文件。
以上是“Spring Boot集成Druid出現異常報錯的原因是什么”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。