亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring Boot集成Druid出現(xiàn)異常報(bào)錯(cuò)的原因及解決

 更新時(shí)間:2021年05月27日 11:20:01   作者:程序新世界  
Druid 可以很好的監(jiān)控 DB 池連接和 SQL 的執(zhí)行情況,天生就是針對(duì)監(jiān)控而生的 DB 連接池。本文講述了Spring Boot集成Druid項(xiàng)目中discard long time none received connection異常的解決方法,出現(xiàn)此問(wèn)題的同學(xué)可以參考下

Spring Boot集成Druid異常

在Spring Boot集成Druid項(xiàng)目中,發(fā)現(xiàn)錯(cuò)誤日志中頻繁的出現(xiàn)如下錯(cuò)誤信息:

discard long time none received connection. , jdbcUrl : jdbc:mysql://******?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8, version : 1.2.3, lastPacketReceivedIdleMillis : 172675

經(jīng)過(guò)排查發(fā)現(xiàn)是Druid版本導(dǎo)致的異常,在1.2.2及以前版本并未出現(xiàn)如此異常。而在其以上版本均存在此問(wèn)題,下面就來(lái)分析一下異常原因及解決方案。

異常分析

首先上面的異常并不影響程序的正常運(yùn)行,但作為程序員看到程序中不停的出現(xiàn)異常還是難以忍受的。所以還是要刨根問(wèn)底的解決一下的。

跟蹤堆棧信息會(huì)發(fā)現(xiàn)對(duì)應(yīng)的異常是從com.alibaba.druid.pool.DruidAbstractDataSource#testConnectionInternal方法中拋出的,對(duì)應(yīng)的代碼如下:

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) 是獲取上一次使用的時(shí)間,mysqlIdleMillis 就是計(jì)算出來(lái)空閑的時(shí)間,timeBetweenEvictionRunsMillis 是常量60秒。如果連接空閑了60秒以上,那就discardConnection(holder) 丟棄這個(gè)舊連接并順帶打印了一個(gè)日志LOG.warn(errorMsg)。

原理追蹤

在上述代碼中,我們看到進(jìn)入該業(yè)務(wù)邏輯是有前提條件的,也就是valid和isMySql變量同時(shí)為true。isMySql為true是必須的,我們使用的本身就是Mysql數(shù)據(jù)庫(kù)。那么是否可以讓valid為false呢?這樣不就不會(huì)進(jìn)入該業(yè)務(wù)處理了嗎?

來(lái)看看valid的來(lái)源,還是在該方法的上面:

boolean valid = validConnectionChecker.isValidConnection(conn, validationQuery, validationQueryTimeout);

我們找到validConnectionChecker的Mysql實(shí)現(xiàn)子類MySqlValidConnectionChecker,該類中對(duì)isValidConnection的實(shí)現(xiàn)如下:

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);
    }

}

我們可以看到上述方法中有三個(gè)返回的地方:第一個(gè)連接已關(guān)閉;第二個(gè)使用ping的形式進(jìn)行檢查;第三,使用select 1的方式進(jìn)行檢查。而使用ping的形式檢查時(shí),無(wú)論是否拋異常都會(huì)返回true。這里我們禁用該模式即可。

進(jìn)入ping的業(yè)務(wù)邏輯主要靠變量usePingMethod來(lái)判斷,追蹤代碼會(huì)發(fā)現(xiàn)在這里進(jìn)行的設(shè)置:

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);
    }
}

那么,也就是說(shuō),當(dāng)我們把系統(tǒng)屬性druid.mysql.usePingMethod設(shè)置為false即可禁用該功能。

禁用Ping Method

找到了問(wèn)題的根源,那么剩下的就是如何禁用了,通常有三種形式。

第一,在啟動(dòng)程序時(shí)在運(yùn)行參數(shù)中增加:-Ddruid.mysql.usePingMethod=false。

第二,在Spring Boot項(xiàng)目中,可在啟動(dòng)類中添加如下靜態(tài)代碼快:

static {
    System.setProperty("druid.mysql.usePingMethod","false");
}

第三,類文件配置。在項(xiàng)目的DruidConfig類中新增加:

/*
* 解決druid 日志報(bào)錯(cuò):discard long time none received connection:xxx
* */
@PostConstruct
public void setProperties(){
    System.setProperty("druid.mysql.usePingMethod","false");
}

至此,已可以成功關(guān)閉該功能,異常信息再也不會(huì)出現(xiàn)了。

為什么要清空空閑60秒以上的連接

猜測(cè),阿里給數(shù)據(jù)庫(kù)設(shè)置的數(shù)據(jù)庫(kù)空閑等待時(shí)間是60秒,mysql數(shù)據(jù)庫(kù)到了空閑等待時(shí)間將關(guān)閉空閑的連接,以提升數(shù)據(jù)庫(kù)服務(wù)器的處理能力。

MySQL的默認(rèn)空閑等待時(shí)間是8小時(shí),就是「wait_timeout」的配置值。如果數(shù)據(jù)庫(kù)主動(dòng)關(guān)閉了空閑的連接,而連接池并不知道,還在使用這個(gè)連接,就會(huì)產(chǎn)生異常。

以上就是Spring Boot集成Druid出現(xiàn)異常報(bào)錯(cuò)的原因及解決的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot集成Druid出現(xiàn)異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java線程池?ThreadPoolExecutor?詳解

    Java線程池?ThreadPoolExecutor?詳解

    這篇文章主要介紹了Java線程池?ThreadPoolExecutor,線程池包括線程集合、阻塞隊(duì)列、拒絕策略處理器,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-07-07
  • Springboot如何實(shí)現(xiàn)代理服務(wù)器

    Springboot如何實(shí)現(xiàn)代理服務(wù)器

    這篇文章主要介紹了Springboot如何實(shí)現(xiàn)代理服務(wù)器問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別及優(yōu)缺點(diǎn)

    Java代理模式之靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別及優(yōu)缺點(diǎn)

    代理模式是一種常用的設(shè)計(jì)模式,它允許通過(guò)引入一個(gè)代理對(duì)象來(lái)控制對(duì)目標(biāo)對(duì)象的訪問(wèn),在Java中,代理模式被廣泛應(yīng)用,它可以提供額外的功能,如權(quán)限檢查、緩存、日志記錄等,本文將介紹靜態(tài)代理與動(dòng)態(tài)代理的區(qū)別及優(yōu)缺點(diǎn),需要的朋友可以參考下
    2023-06-06
  • Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之環(huán)形鏈表

    Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之環(huán)形鏈表

    無(wú)論是靜態(tài)鏈表還是動(dòng)態(tài)鏈表,有時(shí)在解決具體問(wèn)題時(shí),需要我們對(duì)其結(jié)構(gòu)進(jìn)行稍微地調(diào)整。比如,可以把鏈表的兩頭連接,使其成為了一個(gè)環(huán)狀鏈表,通常稱為循環(huán)鏈表
    2022-02-02
  • Java 如何安全的發(fā)布對(duì)象

    Java 如何安全的發(fā)布對(duì)象

    這篇文章主要介紹了Java 如何安全的發(fā)布對(duì)象,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2021-01-01
  • 線程池ThreadPoolExecutor使用簡(jiǎn)介與方法實(shí)例

    線程池ThreadPoolExecutor使用簡(jiǎn)介與方法實(shí)例

    今天小編就為大家分享一篇關(guān)于線程池ThreadPoolExecutor使用簡(jiǎn)介與方法實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • Java List中數(shù)據(jù)的去重

    Java List中數(shù)據(jù)的去重

    今天小編就為大家分享一篇關(guān)于Java List中數(shù)據(jù)的去重,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • SpringBoot org.springframework.beans.factory.UnsatisfiedDependencyException依賴注入異常

    SpringBoot org.springframework.beans.factory.Unsatisfie

    本文主要介紹了SpringBoot org.springframework.beans.factory.UnsatisfiedDependencyException依賴注入異常,文中通過(guò)示例代碼介紹的很詳細(xì),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Java中Shiro安全框架的權(quán)限管理

    Java中Shiro安全框架的權(quán)限管理

    這篇文章主要介紹了Java中Shiro安全框架的權(quán)限管理,Apache?Shiro是Java的一個(gè)安全框架,Shiro可以非常容易的開(kāi)發(fā)出足夠好的應(yīng)用,其不僅可以用在JavaSE環(huán)境,也可以用在JavaEE環(huán)境,需要的朋友可以參考下
    2023-08-08
  • WebDriver實(shí)現(xiàn)自動(dòng)化打開(kāi)IE中的google網(wǎng)頁(yè)并實(shí)現(xiàn)搜索

    WebDriver實(shí)現(xiàn)自動(dòng)化打開(kāi)IE中的google網(wǎng)頁(yè)并實(shí)現(xiàn)搜索

    這篇文章主要介紹了WebDriver實(shí)現(xiàn)自動(dòng)化打開(kāi)IE中的google網(wǎng)頁(yè)并實(shí)現(xiàn)搜索,需要的朋友可以參考下
    2014-04-04

最新評(píng)論