首頁  >  文章  >  Java  >  用alibaba druid進行多資料來源連接時的問題

用alibaba druid進行多資料來源連接時的問題

零下一度
零下一度原創
2017-07-21 17:27:327375瀏覽

用alibaba druid進行多資料來源連線時的問題

標籤(空格分隔):druid springboot start autoconfig


  • 背景

  • 發現、分析過程

  • 總結

#背景

最近在使用alibaba druid進行多資料來源連線的時候無意間發現一個小bug,已經提交github issue 官方已經fix。 issue 位址:

發現、分析流程

我們使用的java開發框架是封裝好的。框架對資料來源的支援是master、slave架構的,就是可以一組多從資料來源,內部會自動進行主從寫入、查詢切換。

我們現在處於.net專java過程中,特殊場景下新java系統需要連接兩個資料來源,預設連接mysql資料來源,但是有時候還需要查詢sqlserver資料來源來取得一些相容性數據。
所以,在設定第二個資料來源的時候,系統load就會報錯。

我們使用springboot框架,datasource config 是基於springboot properties進行設定。然後使用configuration 進行自動druid daasource bean的建立。這看起來好像沒什麼問題。

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {
       return new DruidDataSource();
    }

如果不是springboot,一般都會自己來初始化所有的屬性。從設定檔載入配置,然後手動設定DruidDataSource bean。

沒多想,就直接用這種方式使用了。但是在啟動的時候,初始化bean的時候就報錯了。

'maxEvictableIdleTimeMillis' threw exception; nested exception is java.lang.IllegalArgumentException: maxEvictableIdleTimeMillis must be grater than minEvictabletableIdleTimeMillis

aillis must be grater than minEvictabletableIdleTimeMillis
aillis;必須大於'minEvictableIdleTimeMillis'最小存活時間。

第一反應肯定是配置錯了,檢查配置。

##一个连接在池中最小生存的时间(ms)
ecommon.order.druid.minEvictableIdleTimeMillis=300000
##一个连接在池中最大生存的时间(ms)
ecommon.order.druid.maxEvictableIdleTimeMillis=600000
好像沒錯啊,然後在debug下,問題也同樣出現。 minEvictableIdleTimeMillis屬性和maxEvictableIdleTimeMillis屬性的前後順序好像也沒問題。試試看的心裡,將兩個屬性前後順序交換下,問題還是出現。

蒙蔽狀態~_~。

感覺這個問題有點詭異了,時間要緊,直接找到報錯的地方,進行原始碼追蹤。

上 github search alibaba druid 首頁,直接gith clone下來,定位到錯誤提示的位置。

全域查找的時候有兩處有這個exception的throw。

一: init 方法

public void init() throws SQLException {
            if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
                throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
            }
為了方便閱讀,我刪掉了init中對我們分析問題來說無用的程式碼。

二:setMaxEvictableIdleTimeMillis 方法

    public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
        if (maxEvictableIdleTimeMillis < 1000 * 30) {
            LOG.error("maxEvictableIdleTimeMillis should be greater than 30000");
        }
        
        if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
            throw new IllegalArgumentException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
        }
        
        this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
    }
這兩個方法邏輯都比較簡單,init初始化的時候會檢查這兩個bean屬性的值。 setMaxEvictableIdleTimeMillis,設定這個最大存活時間的時候有一個檢查。如果你的最大存活時間小於最小存活時間直接報錯。

所以直接在這兩個地方打上斷點,然後debug,在追蹤下變數的值基本上就知道問題在哪裡了。

透過debug,發現直接new DruidDataSource()使用資料來源,不會走到init方法。不會進入到觸發報錯的地方。看起來我的程式碼路徑應該不會產生這個檢查。繼續運行,看setMaxEvictableIdleTimeMillis方法什麼狀況。

發現問題了,在進行setMaxEvictableIdleTimeMillis方法的時候,minEvictableIdleTimeMillis屬性的值是1800000。

看下這個值哪來的。

protected volatile long  minEvictableIdleTimeMillis  = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
public static final long  DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 
1000L * 60L * 30L;
minEvictableIdleTimeMillis 屬性有一個default值。單位是ms(millisecond),所以這裡的default 值是30m(minute)分鐘。

我們配置的是600000ms,所以比1800000小。但這個就奇怪了,我們明明設定了minEvictableIdleTimeMillis 參數。為什麼沒起作用,一下子就想到是不是順序問題。

然後繼續debug,先繞過這個檢查,看是不是setMinEvictableIdleTimeMillis 方法在setMaxEvictableIdleTimeMillis 方法之後執行,導致這個檢查和配置順序衝突。

debug下來,確實是這個問題。然後就比較​​好奇,我們現在所使用的這個框架幫我們封裝了druid的時候是怎麼處理的,透過查看框架原始碼,裡面有一個hashcode的排序,解決了這個問題。 (果然老司機,高手)這裡就不展開了。

那我們如果解決這個問題,其實很簡單,知道問題在哪裡繞過去還是很簡單的。

一:先把設定好的minEvictableIdleTimeMillis、maxEvictableIdleTimeMillis取得進來

@Data
@EqualsAndHashCode
@ConfigurationProperties(prefix = "ecommon.order.druid")
public class SqlServerDruidConfig {
    private Long minEvictableIdleTimeMillis;
    private Long maxEvictableIdleTimeMillis;
}
二:然後自己先設定這兩個屬性,springboot autoconfig 的時候就不會出錯

 @Autowired
    private SqlServerDruidConfig druidConfig;

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "ecommon.order.druid")
    public DataSource getOrderDataSource() {

        DruidDataSource dataSource = new DruidDataSource();

        /**setMinEvictableIdleTimeMillis需要先设置*/
        dataSource.setMinEvictableIdleTimeMillis(druidConfig.getMinEvictableIdleTimeMillis());
        dataSource.setMaxEvictableIdleTimeMillis(druidConfig.getMaxEvictableIdleTimeMillis());

        return dataSource;
    }

    @Bean
    public SqlServerDruidConfig getDruidConfig() {
        return new SqlServerDruidConfig();
    }
#rrreee

#問題到這裡分析就結束了。這個小bug,alibaba druid 已經fix。
如果你對如何fix有興趣,請參考druid 有關於autoconfiger修復的程式碼:

總結

突然能明白,其實有關於開源的好處,你已經獲益了。可以一起參與使用,一起參與發現問題,一起參與fixbug。這也許就是linux、git這類優秀藝術品背後的核心技術價值。

以上是用alibaba druid進行多資料來源連接時的問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn