解讀Druid參數(shù)配置全過程
簡介
Java 程序很大一部分要操作數(shù)據(jù)庫,為了提高性能操作數(shù)據(jù)庫的時候,又不得不使用數(shù)據(jù)庫連接池。
- Druid 是阿里巴巴開源平臺上一個數(shù)據(jù)庫連接池實現(xiàn),結(jié)合了 C3P0、DBCP 等 DB 池的優(yōu)點,同時加入了日志監(jiān)控。
- Druid 可以很好的監(jiān)控 DB 池連接和 SQL 的執(zhí)行情況,天生就是針對監(jiān)控而生的 DB 連接池。
- Druid 已經(jīng)在阿里巴巴部署了超過600個應用,經(jīng)過一年多生產(chǎn)環(huán)境大規(guī)模部署的嚴苛考驗。
- Spring Boot 2.0 以上默認使用 Hikari 數(shù)據(jù)源,Hikari 與 Driud 都是當前 Java Web 上最優(yōu)秀的數(shù)據(jù)源。
連接
當我們程序需要訪問數(shù)據(jù)庫時,需要創(chuàng)建一個本地到數(shù)據(jù)庫服務的網(wǎng)絡(luò)連接,此時本地代碼就相當于一個數(shù)據(jù)庫的客戶端,可以通過這個連接去訪問數(shù)據(jù)、執(zhí)行sql,
如下所示:
Driver driver = new com.mysql.cj.jdbc.Driver();
// 創(chuàng)建連接
Connection con = driver.connect(JDBC_URL, props);
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery("show tables");
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
con.close();池化技術(shù)
由于我們的代碼需要不斷與數(shù)據(jù)庫交互讀取數(shù)據(jù),如果每次請求數(shù)據(jù)都創(chuàng)建一個連接的話,網(wǎng)絡(luò)開銷是很大的,也會導致我們的程序比較慢,同時連接如果太多也會給數(shù)據(jù)庫造成壓力
為了解決這個問題,就有了池化技術(shù),把創(chuàng)建好的連接放在池里,用時去池里獲取,節(jié)省了創(chuàng)建連接的時間,也可以通過配置來限定池的最大連接數(shù)等

連接池最常用的工具基本就是阿里的Druid了,簡單使用如下
// druid 數(shù)據(jù)源
DruidDataSource druidDataSource = new DruidDataSource();
// 數(shù)據(jù)源配置
druidDataSource.setUrl(JDBC_URL);
druidDataSource.setUsername(USERNAME);
druidDataSource.setPassword(PASSWORD);
// 初始化
druidDataSource.init();
// 獲取表名
Connection con = druidDataSource.getConnection();
Statement statement = con.createStatement();
ResultSet resultSet = statement.executeQuery("show tables");
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
con.close();可以看到使用了Druid,獲取連接不再是直接使用驅(qū)動創(chuàng)建連接,而是通過DruidDataSource對象獲取連接。
參數(shù)配置及說明
| 配置項名稱 | 缺省值 | 說明 | java set方法定義 |
|---|---|---|---|
| connectProperties | {} | map方式放入自定義的key和value,在Filter等地方可以獲取該信息進行相應邏輯控制 | public void com.alibaba.druid.pool.DruidDataSource.setConnectProperties(java.util.Properties) |
| connectionProperties | null | 字符串方式放入自定義的key和value,鍵值對用分號隔開,比如“a=b;c=d”,傳入空白字符串表示清空屬性,實際拆分字符串后賦值給connectProperties,在Filter等地方可以獲取該信息進行相應邏輯控制 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setConnectionProperties(java.lang.String) |
| connectTimeout | 0 | 新增的控制創(chuàng)建連接時的socket連接最大等待超時,單位是毫秒,默認0表示永遠等待,工作原理是在創(chuàng)建連接時將該值設(shè)置到對應數(shù)據(jù)庫驅(qū)動的屬性信息中由其JDBC驅(qū)動進行控制 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setConnectTimeout(int) |
| connectionInitSqls | [] | 數(shù)組方式定義物理連接初始化的時候執(zhí)行的1到多條sql語句,比如連接MySQL數(shù)據(jù)庫使用低版本驅(qū)動的情況下,想使用utf8mb4,則可以配置sql為: set NAMES 'utf8mb4' | public void com.alibaba.druid.pool.DruidAbstractDataSource.setConnectionInitSqls(java.util.Collection) |
| createScheduler | null | 可以使用定時線程池方式異步創(chuàng)建連接,比起默認的單線程創(chuàng)建連接方式,經(jīng)實際驗證這種更可靠 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setCreateScheduler(java.util.concurrent.ScheduledExecutorService) |
| dbType | null | 對于不是Druid自動適配支持的db類型,可以強制指定db類型,字符串值來自com.alibaba.druid.DbType的枚舉名 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setDbType(java.lang.String) |
| destroyScheduler | null | 可以使用定時線程池方式異步創(chuàng)建連接,比起默認的單線程創(chuàng)建連接方式,經(jīng)實際驗證這種更可靠 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setDestroyScheduler(java.util.concurrent.ScheduledExecutorService) |
| driverClassName | 根據(jù)url自動識別 | 這一項可配可不配,如果不配置druid會根據(jù)url自動識別dbType,然后選擇相應的driverClassName | com.alibaba.druid.pool.DruidAbstractDataSource.setDriverClassName(String) |
| exceptionSorter | null | 當數(shù)據(jù)庫拋出一些不可恢復的異常時,拋棄連接 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setExceptionSorter(com.alibaba.druid.pool.ExceptionSorter) |
| failFast | false | null | public void com.alibaba.druid.pool.DruidAbstractDataSource.setFailFast(boolean) |
| filters | 屬性類型是逗號隔開的字符串,通過別名的方式配置擴展插件,插件別名列表請參考druid jar包中的 /META-INF/druid-filter.properties,常用的插件有: 監(jiān)控統(tǒng)計用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall 防御sql注入的filter:wall | com.alibaba.druid.pool.DruidAbstractDataSource.setFilters(String) | |
| initialSize | 0 | 初始化數(shù)據(jù)源時建立物理連接的個數(shù)。初始化發(fā)生在顯示調(diào)用init方法,或者第一次getConnection時 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setInitialSize(int) |
| keepAlive | false | 連接池中的minIdle數(shù)量以內(nèi)的連接,空閑時間超過minEvictableIdleTimeMillis,則會執(zhí)行keepAlive操作。實際項目中建議配置成true | public void com.alibaba.druid.pool.DruidDataSource.setKeepAlive(boolean) |
| keepAliveBetweenTimeMillis | 120000 | null | public void com.alibaba.druid.pool.DruidAbstractDataSource.setKeepAliveBetweenTimeMillis(long) |
| logAbandoned | false | 在開啟removeAbandoned為true的情況,可以開啟該設(shè)置,druid在銷毀未及時關(guān)閉的連接時,則會輸出日志信息,便于定位連接泄露問題 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setLogAbandoned(boolean) |
| loginTimeout | 單位是秒,底層調(diào)用DriverManager全局靜態(tài)方法 | java.sql.DriverManager.setLoginTimeout(int) | |
| maxActive | 8 | 連接池最大活躍連接數(shù)量,當連接數(shù)量達到該值時,再獲取新連接時,將處于等待狀態(tài),直到有連接被釋放,才能借用成功 | public void com.alibaba.druid.pool.DruidDataSource.setMaxActive(int) |
| maxEvictableIdleTimeMillis | 25200000 | null | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMaxEvictableIdleTimeMillis(long) |
| maxIdle | 8 | 已經(jīng)徹底廢棄,配置了也沒效果,以maxActive為準 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMaxIdle(int) |
| maxOpenPreparedStatements | 10 | null | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMaxOpenPreparedStatements(int) |
| maxPoolPreparedStatementPerConnectionSize | 10 | 要啟用PSCache,必須配置大于0,當大于0時,poolPreparedStatements自動觸發(fā)修改為true。在Druid中,不會存在Oracle下PSCache占用內(nèi)存過多的問題,可以把這個數(shù)值配置大一些,比如說100 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMaxPoolPreparedStatementPerConnectionSize(int) |
| maxWait | -1 | 獲取連接時最大等待時間,單位毫秒。配置了maxWait之后,缺省啟用公平鎖,并發(fā)效率會有所下降,如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMaxWait(long) |
| minEvictableIdleTimeMillis | 1800000 | 連接保持空閑而不被驅(qū)逐的最小時間 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMinEvictableIdleTimeMillis(long) |
| minIdle | 0 | 連接池最小空閑數(shù)量 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setMinIdle(int) |
| name | DataSource-**** | 配置這個屬性的意義在于,如果存在多個數(shù)據(jù)源,監(jiān)控的時候可以通過名字來區(qū)分開來。如果沒有配置,將會生成一個名字,格式是:"DataSource-" + System.identityHashCode(this). 另外配置此屬性至少在1.0.5版本中是不起作用的,強行設(shè)置name會出錯。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setName(java.lang.String) |
| numTestsPerEvictionRun | 3 | 不再使用,已經(jīng)徹底廢棄,一個DruidDataSource只支持一個EvictionRun | public void com.alibaba.druid.pool.DruidAbstractDataSource.setNumTestsPerEvictionRun(int) |
| password | null | 連接數(shù)據(jù)庫的密碼。如果你不希望密碼直接寫在配置文件中,可以使用passwordCallback進行配置,或者使用ConfigFilter。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setPassword(java.lang.String) |
| passwordCallback | null | 可以自定義實現(xiàn)定制的PasswordCallback,然后實現(xiàn)定制的密碼解密效果 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setPasswordCallback(javax.security.auth.callback.PasswordCallback) |
| phyTimeoutMillis | -1 | 強制回收物理連接的最大超時時長,大于0的情況下才生效,當物理創(chuàng)建之后存活的時長超過該值時,該連接會強制銷毀,便于重新創(chuàng)建新連接,建議可以配置成7小時的毫秒值,比如25200000,這樣可以規(guī)避MySQL的8小時連接斷開問題 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setPhyTimeoutMillis(long) |
| poolPreparedStatements | false | 是否緩存preparedStatement,也就是PSCache。PSCache對支持游標的數(shù)據(jù)庫性能提升巨大,比如說oracle。在mysql下建議關(guān)閉。 | public void com.alibaba.druid.pool.DruidDataSource.setPoolPreparedStatements(boolean) |
| proxyFilters | 類型是List<com.alibaba.druid.filter.Filter>,如果同時配置了filters和proxyFilters,是組合關(guān)系,并非替換關(guān)系 | com.alibaba.druid.pool.DruidAbstractDataSource.setProxyFilters(List) | |
| queryTimeout | 0 | 控制查詢結(jié)果的最大超時,單位是秒,大于0才生效,最終底層調(diào)用是java.sql.Statement.setQueryTimeout(int) | public void com.alibaba.druid.pool.DruidAbstractDataSource.setQueryTimeout(int) |
| removeAbandoned | false | 是否回收泄露的連接,默認不開啟,建議只在測試環(huán)境設(shè)置未開啟,利用測試環(huán)境發(fā)現(xiàn)業(yè)務代碼中未正常關(guān)閉連接的情況 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setRemoveAbandoned(boolean) |
| removeAbandonedTimeoutMillis | 300000 | 開啟回收泄露連接的最大超時,默認300秒表示連接被借出超過5分鐘后,且removeAbandoned開啟的情況下,強制關(guān)閉該泄露連接 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setRemoveAbandonedTimeoutMillis(long) |
| socketTimeout | 0 | 新增的控制創(chuàng)建連接時的socket最大讀超時,單位是毫秒,默認0表示永遠等待,配置成10000則表示db操作如果在10秒內(nèi)未返回應答,將拋出異常,工作原理是在創(chuàng)建連接時將該值設(shè)置到對應數(shù)據(jù)庫驅(qū)動的屬性信息中由其JDBC驅(qū)動進行控制 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setSocketTimeout(int) |
| testOnBorrow | false | 申請連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能,其實一般情況下都可以開啟,只有性能要求極其高且連接使用很頻繁的情況下才有必要禁用。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setTestOnBorrow(boolean) |
| testOnReturn | false | 歸還連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能,這個一般不需要開啟。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setTestOnReturn(boolean) |
| testWhileIdle | true | 建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setTestWhileIdle(boolean) |
| timeBetweenEvictionRunsMillis | 60000 | 有兩個含義: 1) Destroy線程會檢測連接的間隔時間,如果連接空閑時間大于等于minEvictableIdleTimeMillis則關(guān)閉物理連接。 2) testWhileIdle的判斷依據(jù),詳細看testWhileIdle屬性的說明 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setTimeBetweenEvictionRunsMillis(long) |
| transactionQueryTimeout | 0 | 控制查詢結(jié)果的最大超時,單位是秒,大于0才生效,最終是在開啟事務的情況下底層調(diào)用java.sql.Statement.setQueryTimeout(int) | public void com.alibaba.druid.pool.DruidAbstractDataSource.setTransactionQueryTimeout(int) |
| url | 連接數(shù)據(jù)庫的url,不同數(shù)據(jù)庫不一樣。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | com.alibaba.druid.pool.DruidAbstractDataSource.setUrl(String) | |
| username | null | 連接數(shù)據(jù)庫的用戶名 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setUsername(java.lang.String) |
| validationQuery | null | 用來檢測連接是否有效的sql,要求是一個查詢語句,常用select 'x'。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會起作用。 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setValidationQuery(java.lang.String) |
| validationQueryTimeout | -1 | 單位:秒,檢測連接是否有效的超時時間,大于0才生效。底層調(diào)用jdbc Statement對象的void setQueryTimeout(int seconds)方法 | public void com.alibaba.druid.pool.DruidAbstractDataSource.setValidationQueryTimeout(int) |
實際配置示例
Spring Boot 方式(推薦)
依賴
<!--引入druid數(shù)據(jù)源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>連接池配置:
spring:
datasource:
#數(shù)據(jù)源基本配置
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_crud
type: com.alibaba.druid.pool.DruidDataSource
#數(shù)據(jù)源其他配置
druid:
#配置初始化大小、最小、最大線程數(shù)
initialSize: 5
minIdle: 5
#CPU核數(shù)+1,也可以大些但不要超過20,數(shù)據(jù)庫加鎖時連接過多性能下降
maxActive: 20
# 最大等待時間,內(nèi)網(wǎng):800,外網(wǎng):1200(三次握手1s)
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
#配置一個連接在池中最大空間時間,單位是毫秒
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1
testWhileIdle: true
# 設(shè)置從連接池獲取連接時是否檢查連接有效性,true檢查,false不檢查
testOnBorrow: true
# 設(shè)置從連接池歸還連接時是否檢查連接有效性,true檢查,false不檢查
testOnReturn: true
#可以支持PSCache(提升寫入、查詢效率)
poolPreparedStatements: true
#配置監(jiān)控統(tǒng)計攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計,'wall'用于防火墻
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500實現(xiàn)密碼加密
目前配置文件中配置的數(shù)據(jù)庫用戶名和密碼都是明文的,這在某些情況下是不被允許的,那正好druid可以對其進行加密,按以下操作即可:
- 利用工具類生成加密后密碼和公鑰
public static void main(String[] args) throws Exception {
String password = "root123";
System.out.println("明文密碼: " + password);
String[] keyPair = ConfigTools.genKeyPair(512);
//私鑰
String privateKey = keyPair[0];
//公鑰
String publicKey = keyPair[1];
//用私鑰加密后的密文
password = ConfigTools.encrypt(privateKey, password);
System.out.println("privateKey:" + privateKey);
System.out.println("publicKey:" + publicKey);
System.out.println("password:" + password);
String decryptPassword = ConfigTools.decrypt(publicKey, password);
System.out.println("解密后:" + decryptPassword);
}
運行后得到:

利用命令加密
java -cp D:/xxxx/druid-1.2.8/druid-1.2.8.jar com.alibaba.druid.filter.config.ConfigTools root java -cp D:/xxxx/druid-1.2.8/druid-1.2.8.jar com.alibaba.druid.filter.config.ConfigTools 123456
注:123456為你數(shù)據(jù)庫的密碼

對我們有用的是publicKey和加密后的password,這個publickey主要是用來解密的秘鑰
- 修改配置文件
用上面得到的密碼和publicKey替換配置文件中的密文:
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKXfJyPsQ1rvSQXO+8m1TrIWS5XSSwzwDBIjPGZNbpZ10+Tai7k1GMzF6eufgMNWlNwOHJvxIYwjrts8b4UbSiECAwEAAQ==
druid:
url: jdbc:mysql://lcoahost:3306/test1?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: ENC(EChlZH6XdPa129Ii3akF/92alTAIifYXdbFJaqKlmcQNF0a/QRoaAook16eO72vw4S4Ut8nXeoGOMdgFkQuW+A==)
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
#validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
enabled: true
url-pattern: /druid/*
#login-username: admin
#login-password: admin
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
config:
enabled: true
connection-properties: config.decrypt=true;config.decrypt.key=${spring.datasource.publicKey}配置文件跟加密相關(guān)的屬性
spring.datasource.druid.connection-properties
這個屬性配置的value是鍵值對,其中config.decrypt=true表示要進行解密,config.decrypt.key=${spring.datasource.publicKey}注入要解密需要的公鑰
spring.datasource.druid.filter.config.enabled=true
開啟configFilter, 這個不開啟是沒辦法進行解密操作的
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot使用log4j2將日志記錄到文件及自定義數(shù)據(jù)庫的配置方法
這篇文章主要介紹了SpringBoot使用log4j2將日志記錄到文件及自定義數(shù)據(jù)庫的配置方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03
Springboot整合Java?DL4J實現(xiàn)交通標志識別系統(tǒng)全過程
在自動駕駛系統(tǒng)中,交通標志識別是實現(xiàn)車輛智能化的關(guān)鍵技術(shù)之一,本文介紹了利用SpringBoot和JavaDeeplearning4j構(gòu)建交通標志識別系統(tǒng)的方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-10-10
關(guān)于@MapperScan和@ComponentScan的使用問題
文章介紹了在使用`@MapperScan`和`@ComponentScan`時可能會遇到的包掃描沖突問題,并提供了解決方法,同時,還詳細解釋了`@MapperScan`和`@ComponentScan`的功能和使用場景2025-01-01
SpringSecurity中的Filter Chain(過濾器鏈)
Spring Security的Filter Chain是由一系列過濾器組成的管道,每個過濾器執(zhí)行特定的安全功能,Spring Security能夠提供強大而靈活的安全控制機制,從而保護你的應用程序不受各種網(wǎng)絡(luò)安全威脅的侵害,本文介紹SpringSecurity中的Filter Chain,感興趣的朋友跟隨小編一起看看吧2024-06-06
Spring?Boot虛擬線程Webflux在JWT驗證和MySQL查詢性能比較
這篇文章主要為大家介紹了Spring Boot虛擬線程與Webflux在JWT驗證和MySQL查詢上的性能比較,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
springboot+rabbitmq實現(xiàn)智能家居實例詳解
這篇文章主要為大家介紹了springboot+rabbitmq實現(xiàn)智能家居的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07

