Spring Boot 2.x基礎(chǔ)教程:使用國(guó)產(chǎn)數(shù)據(jù)庫(kù)連接池Druid

上一節(jié),我們介紹了Spring Boot在JDBC模塊中自動(dòng)化配置使用的默認(rèn)數(shù)據(jù)源HikariCP。接下來(lái)這一節(jié),我們將介紹另外一個(gè)被廣泛應(yīng)用的開(kāi)源數(shù)據(jù)源:Druid碉克。

Druid是由阿里巴巴數(shù)據(jù)庫(kù)事業(yè)部出品的開(kāi)源項(xiàng)目。它除了是一個(gè)高性能數(shù)據(jù)庫(kù)連接池之外并齐,更是一個(gè)自帶監(jiān)控的數(shù)據(jù)庫(kù)連接池漏麦。雖然HikariCP已經(jīng)很優(yōu)秀,但是對(duì)于國(guó)內(nèi)用戶來(lái)說(shuō)况褪,可能對(duì)于Druid更為熟悉撕贞。所以,對(duì)于如何在Spring Boot中使用Druid是后端開(kāi)發(fā)人員必須要掌握的基本技能测垛。

配置Druid數(shù)據(jù)源

這一節(jié)的實(shí)踐我們將基于《Spring Boot 2.x基礎(chǔ)教程:使用JdbcTemplate訪問(wèn)MySQL數(shù)據(jù)庫(kù)》一文的代碼基礎(chǔ)上進(jìn)行麻掸。所以,讀者可以從文末的代碼倉(cāng)庫(kù)中赐纱,檢出chapter3-1目錄來(lái)進(jìn)行下面的實(shí)踐學(xué)習(xí)脊奋。

下面我們就來(lái)開(kāi)始對(duì)Spring Boot項(xiàng)目配置Druid數(shù)據(jù)源:

第一步:在pom.xml中引入druid官方提供的Spring Boot Starter封裝。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.21</version>
</dependency>

第二步:在application.properties中配置數(shù)據(jù)庫(kù)連接信息疙描。

Druid的配置都以spring.datasource.druid作為前綴诚隙,所以根據(jù)之前的配置,稍作修改即可:

spring.datasource.druid.url=jdbc:mysql://localhost:3306/test
spring.datasource.druid.username=root
spring.datasource.druid.password=
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver

第三步:配置Druid的連接池起胰。

與Hikari一樣久又,要用好一個(gè)數(shù)據(jù)源,就要對(duì)其連接池做好相應(yīng)的配置效五,比如下面這樣:

spring.datasource.druid.initialSize=10
spring.datasource.druid.maxActive=20
spring.datasource.druid.maxWait=60000
spring.datasource.druid.minIdle=1
spring.datasource.druid.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.minEvictableIdleTimeMillis=300000
spring.datasource.druid.testWhileIdle=true
spring.datasource.druid.testOnBorrow=true
spring.datasource.druid.testOnReturn=false
spring.datasource.druid.poolPreparedStatements=true
spring.datasource.druid.maxOpenPreparedStatements=20
spring.datasource.druid.validationQuery=SELECT 1
spring.datasource.druid.validation-query-timeout=500
spring.datasource.druid.filters=stat

關(guān)于Druid中各連接池配置的說(shuō)明可查閱下面的表格:

配置 缺省值 說(shuō)明
name 配置這個(gè)屬性的意義在于地消,如果存在多個(gè)數(shù)據(jù)源,監(jiān)控的時(shí)候可以通過(guò)名字來(lái)區(qū)分開(kāi)來(lái)畏妖。如果沒(méi)有配置脉执,將會(huì)生成一個(gè)名字,格式是:”DataSource-“ + System.identityHashCode(this). 另外配置此屬性至少在1.0.5版本中是不起作用的戒劫,強(qiáng)行設(shè)置name會(huì)出錯(cuò)半夷。詳情-點(diǎn)此處
url 連接數(shù)據(jù)庫(kù)的url迅细,不同數(shù)據(jù)庫(kù)不一樣巫橄。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username 連接數(shù)據(jù)庫(kù)的用戶名
password 連接數(shù)據(jù)庫(kù)的密碼。如果你不希望密碼直接寫在配置文件中茵典,可以使用ConfigFilter湘换。詳細(xì)看這里
driverClassName 根據(jù)url自動(dòng)識(shí)別 這一項(xiàng)可配可不配,如果不配置druid會(huì)根據(jù)url自動(dòng)識(shí)別dbType,然后選擇相應(yīng)的driverClassName
initialSize 0 初始化時(shí)建立物理連接的個(gè)數(shù)彩倚。初始化發(fā)生在顯示調(diào)用init方法筹我,或者第一次getConnection時(shí)
maxActive 8 最大連接池?cái)?shù)量
maxIdle 8 已經(jīng)不再使用,配置了也沒(méi)效果
minIdle 最小連接池?cái)?shù)量
maxWait 獲取連接時(shí)最大等待時(shí)間署恍,單位毫秒。配置了maxWait之后蜻直,缺省啟用公平鎖盯质,并發(fā)效率會(huì)有所下降,如果需要可以通過(guò)配置useUnfairLock屬性為true使用非公平鎖概而。
poolPreparedStatements false 是否緩存preparedStatement呼巷,也就是PSCache。PSCache對(duì)支持游標(biāo)的數(shù)據(jù)庫(kù)性能提升巨大赎瑰,比如說(shuō)oracle王悍。在mysql下建議關(guān)閉。
maxPoolPreparedStatementPerConnectionSize -1 要啟用PSCache餐曼,必須配置大于0压储,當(dāng)大于0時(shí),poolPreparedStatements自動(dòng)觸發(fā)修改為true源譬。在Druid中集惋,不會(huì)存在Oracle下PSCache占用內(nèi)存過(guò)多的問(wèn)題,可以把這個(gè)數(shù)值配置大一些踩娘,比如說(shuō)100
validationQuery 用來(lái)檢測(cè)連接是否有效的sql刮刑,要求是一個(gè)查詢語(yǔ)句,常用select ‘x’养渴。如果validationQuery為null雷绢,testOnBorrow、testOnReturn理卑、testWhileIdle都不會(huì)起作用翘紊。
validationQueryTimeout 單位:秒,檢測(cè)連接是否有效的超時(shí)時(shí)間藐唠。底層調(diào)用jdbc Statement對(duì)象的void setQueryTimeout(int seconds)方法
testOnBorrow true 申請(qǐng)連接時(shí)執(zhí)行validationQuery檢測(cè)連接是否有效霞溪,做了這個(gè)配置會(huì)降低性能。
testOnReturn false 歸還連接時(shí)執(zhí)行validationQuery檢測(cè)連接是否有效中捆,做了這個(gè)配置會(huì)降低性能鸯匹。
testWhileIdle false 建議配置為true,不影響性能泄伪,并且保證安全性殴蓬。申請(qǐng)連接的時(shí)候檢測(cè),如果空閑時(shí)間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測(cè)連接是否有效染厅。
keepAlive false (1.0.28) 連接池中的minIdle數(shù)量以內(nèi)的連接痘绎,空閑時(shí)間超過(guò)minEvictableIdleTimeMillis,則會(huì)執(zhí)行keepAlive操作肖粮。
timeBetweenEvictionRunsMillis 1分鐘(1.0.14) 有兩個(gè)含義: 1) Destroy線程會(huì)檢測(cè)連接的間隔時(shí)間孤页,如果連接空閑時(shí)間大于等于minEvictableIdleTimeMillis則關(guān)閉物理連接。 2) testWhileIdle的判斷依據(jù)涩馆,詳細(xì)看testWhileIdle屬性的說(shuō)明
numTestsPerEvictionRun 30分鐘(1.0.14) 不再使用行施,一個(gè)DruidDataSource只支持一個(gè)EvictionRun
minEvictableIdleTimeMillis 連接保持空閑而不被驅(qū)逐的最小時(shí)間
connectionInitSqls 物理連接初始化的時(shí)候執(zhí)行的sql
exceptionSorter 根據(jù)dbType自動(dòng)識(shí)別 當(dāng)數(shù)據(jù)庫(kù)拋出一些不可恢復(fù)的異常時(shí),拋棄連接
filters 屬性類型是字符串魂那,通過(guò)別名的方式配置擴(kuò)展插件蛾号,常用的插件有: 監(jiān)控統(tǒng)計(jì)用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall
proxyFilters 類型是List<com.alibaba.druid.filter.Filter>,如果同時(shí)配置了filters和proxyFilters涯雅,是組合關(guān)系鲜结,并非替換關(guān)系

到這一步,就已經(jīng)完成了將Spring Boot的默認(rèn)數(shù)據(jù)源HikariCP切換到Druid的所有操作活逆。

配置Druid監(jiān)控

既然用了Druid精刷,那么對(duì)于Druid的監(jiān)控功能怎么能不用一下呢?下面就來(lái)再進(jìn)一步做一些配置蔗候,來(lái)啟用Druid的監(jiān)控贬养。

第一步:在pom.xml中引入spring-boot-starter-actuator模塊

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

第二步:在application.properties中添加Druid的監(jiān)控配置。

spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.reset-enable=true
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin

上面的配置主要用于開(kāi)啟stat監(jiān)控統(tǒng)計(jì)的界面以及監(jiān)控內(nèi)容的相關(guān)配置琴庵,具體釋意如下:

  • spring.datasource.druid.stat-view-servlet.url-pattern:訪問(wèn)地址規(guī)則
  • spring.datasource.druid.stat-view-servlet.reset-enable:是否允許清空統(tǒng)計(jì)數(shù)據(jù)
  • spring.datasource.druid.stat-view-servlet.login-username:監(jiān)控頁(yè)面的登錄賬戶
  • spring.datasource.druid.stat-view-servlet.login-password:監(jiān)控頁(yè)面的登錄密碼

第三步:針對(duì)之前實(shí)現(xiàn)的UserService內(nèi)容误算,我們創(chuàng)建一個(gè)Controller來(lái)通過(guò)接口去調(diào)用數(shù)據(jù)訪問(wèn)操作:

@Data
@AllArgsConstructor
@RestController
public class UserController {

    private UserService userService;

    @PostMapping("/user")
    public int create(@RequestBody User user) {
        return userService.create(user.getName(), user.getAge());
    }

    @GetMapping("/user/{name}")
    public List<User> getByName(@PathVariable String name) {
        return userService.getByName(name);
    }

    @DeleteMapping("/user/{name}")
    public int deleteByName(@PathVariable String name) {
        return userService.deleteByName(name);
    }

    @GetMapping("/user/count")
    public int getAllUsers() {
        return userService.getAllUsers();
    }

    @DeleteMapping("/user/all")
    public int deleteAllUsers() {
        return userService.deleteAllUsers();
    }

}

第四步:完成上面所有配置之后,啟動(dòng)應(yīng)用迷殿,訪問(wèn)Druid的監(jiān)控頁(yè)面http://localhost:8080/druid/儿礼,可以看到如下登錄頁(yè)面:

img

輸入上面spring.datasource.druid.stat-view-servlet.login-usernamespring.datasource.druid.stat-view-servlet.login-password配置的登錄賬戶與密碼,就能看到如下監(jiān)控頁(yè)面:

img

進(jìn)入到這邊時(shí)候庆寺,就可以看到對(duì)于應(yīng)用端而言的各種監(jiān)控?cái)?shù)據(jù)了蚊夫。這里講解幾個(gè)最為常用的監(jiān)控頁(yè)面:

數(shù)據(jù)源:這里可以看到之前我們配置的數(shù)據(jù)庫(kù)連接池信息以及當(dāng)前使用情況的各種指標(biāo)。

img

SQL監(jiān)控:該數(shù)據(jù)源中執(zhí)行的SQL語(yǔ)句極其統(tǒng)計(jì)數(shù)據(jù)懦尝。在這個(gè)頁(yè)面上知纷,我們可以很方便的看到當(dāng)前這個(gè)Spring Boot都執(zhí)行過(guò)哪些SQL,這些SQL的執(zhí)行頻率和執(zhí)行效率也都可以清晰的看到陵霉。如果你這里沒(méi)看到什么數(shù)據(jù)琅轧?別忘了我們之前創(chuàng)建了一個(gè)Controller,用這些接口可以觸發(fā)UserService對(duì)數(shù)據(jù)庫(kù)的操作踊挠。所以乍桂,這里我們可以通過(guò)調(diào)用接口的方式去觸發(fā)一些操作,這樣SQL監(jiān)控頁(yè)面就會(huì)產(chǎn)生一些數(shù)據(jù):

img

圖中監(jiān)控項(xiàng)上,執(zhí)行時(shí)間睹酌、讀取行數(shù)权谁、更新行數(shù)都通過(guò)區(qū)間分布的方式表示,將耗時(shí)分布成8個(gè)區(qū)間:

  • 0 - 1 耗時(shí)0到1毫秒的次數(shù)
  • 1 - 10 耗時(shí)1到10毫秒的次數(shù)
  • 10 - 100 耗時(shí)10到100毫秒的次數(shù)
  • 100 - 1,000 耗時(shí)100到1000毫秒的次數(shù)
  • 1,000 - 10,000 耗時(shí)1到10秒的次數(shù)
  • 10,000 - 100,000 耗時(shí)10到100秒的次數(shù)
  • 100,000 - 1,000,000 耗時(shí)100到1000秒的次數(shù)
  • 1,000,000 - 耗時(shí)1000秒以上的次數(shù)

記錄耗時(shí)區(qū)間的發(fā)生次數(shù)憋沿,通過(guò)區(qū)分分布旺芽,可以很方便看出SQL運(yùn)行的極好、普通和極差的分布辐啄。 耗時(shí)區(qū)分分布提供了“執(zhí)行+RS時(shí)分布”采章,是將執(zhí)行時(shí)間+ResultSet持有時(shí)間合并監(jiān)控,這個(gè)能方便診斷返回行數(shù)過(guò)多的查詢则披。

SQL防火墻:該頁(yè)面記錄了與SQL監(jiān)控不同維度的監(jiān)控?cái)?shù)據(jù)共缕,更多用于對(duì)表訪問(wèn)維度洗出、SQL防御維度的統(tǒng)計(jì)士复。

img

該功能數(shù)據(jù)記錄的統(tǒng)計(jì)需要在spring.datasource.druid.filters中增加wall屬性才會(huì)進(jìn)行記錄統(tǒng)計(jì),比如這樣:

spring.datasource.druid.filters=stat,wall

注意:這里的所有監(jiān)控信息是對(duì)這個(gè)應(yīng)用實(shí)例的數(shù)據(jù)源而言的翩活,而并不是數(shù)據(jù)庫(kù)全局層面的阱洪,可以視為應(yīng)用層的監(jiān)控,不可能作為中間件層的監(jiān)控菠镇。

代碼示例

本文的相關(guān)例子可以查看下面?zhèn)}庫(kù)中的chapter3-3目錄:

如果您覺(jué)得本文不錯(cuò)冗荸,歡迎Star支持,您的關(guān)注是我堅(jiān)持的動(dòng)力利耍!

歡迎關(guān)注我的公眾號(hào):程序猿DD蚌本,獲得獨(dú)家整理的學(xué)習(xí)資源和日常干貨推送。
如果您對(duì)我的專題內(nèi)容感興趣隘梨,也可以關(guān)注我的博客:didispace.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末程癌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子轴猎,更是在濱河造成了極大的恐慌嵌莉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捻脖,死亡現(xiàn)場(chǎng)離奇詭異锐峭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)可婶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門沿癞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人矛渴,你說(shuō)我怎么就攤上這事抛寝。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵盗舰,是天一觀的道長(zhǎng)晶府。 經(jīng)常有香客問(wèn)我,道長(zhǎng)钻趋,這世上最難降的妖魔是什么川陆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蛮位,結(jié)果婚禮上较沪,老公的妹妹穿的比我還像新娘。我一直安慰自己失仁,他們只是感情好尸曼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著萄焦,像睡著了一般控轿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拂封,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天茬射,我揣著相機(jī)與錄音,去河邊找鬼冒签。 笑死在抛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萧恕。 我是一名探鬼主播刚梭,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼票唆!你這毒婦竟也來(lái)了朴读?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惰说,失蹤者是張志新(化名)和其女友劉穎磨德,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吆视,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡典挑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啦吧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片您觉。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖授滓,靈堂內(nèi)的尸體忽然破棺而出琳水,到底是詐尸還是另有隱情肆糕,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布在孝,位于F島的核電站诚啃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏私沮。R本人自食惡果不足惜始赎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仔燕。 院中可真熱鬧造垛,春花似錦、人聲如沸晰搀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)外恕。三九已至杆逗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吁讨,已是汗流浹背髓迎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工峦朗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留建丧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓波势,卻偏偏與公主長(zhǎng)得像翎朱,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尺铣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容