javascript
Spring Boot 数据库连接池入门
本文在提供完整代碼示例,可見(jiàn) https://github.com/YunaiV/SpringBoot-Labs 的 lab-19 目錄。
原創(chuàng)不易,給點(diǎn)個(gè) Star 嘿,一起沖鴨!
1. 概述
在我們的項(xiàng)目中,數(shù)據(jù)庫(kù)連接池基本是必不可少的組件。在目前數(shù)據(jù)庫(kù)連接池的選型中,主要是
-
Druid ,為監(jiān)控而生的數(shù)據(jù)庫(kù)連接池。
-
HikariCP ,號(hào)稱(chēng)性能最好的數(shù)據(jù)庫(kù)連接池。
至于怎么選擇,兩者都非常優(yōu)秀,不用過(guò)多糾結(jié)。
-
Spring Boot 2.X 版本,默認(rèn)采用 HikariCP 。
-
阿里大規(guī)模采用 Druid 。
當(dāng)然,如下有一些資料,胖友可以閱讀參考:
-
《Druid 連接池介紹》
-
《為什么 HikariCP 被號(hào)稱(chēng)為性能最好的 Java 數(shù)據(jù)庫(kù)連接池,如何配置使用》
-
《alibaba/druid pool analysis》 ,一個(gè)小小的“撕逼”。
下面,我們來(lái)進(jìn)行 HikariCP 和 Druid 的入門(mén),會(huì)配置單數(shù)據(jù)源和多數(shù)據(jù)源情況下的連接池。
2. HikariCP 單數(shù)據(jù)源
示例代碼對(duì)應(yīng)倉(cāng)庫(kù):lab-19-datasource-pool-hikaricp-single 。
在本小節(jié),我們會(huì)使用配置一個(gè)數(shù)據(jù)源的 HikariCP 連接池。
艿艿:推薦入門(mén)后,可以看看 HikariCP 的文檔:https://github.com/brettwooldridge/HikariCP/wiki 。
2.1 引入依賴(lài)
在?pom.xml?文件中,引入相關(guān)依賴(lài)。
<?xml?version="1.0"?encoding="UTF-8"?> <project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/>?<!--?lookup?parent?from?repository?--></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-19-datasource-pool-hikaricp-single</artifactId><dependencies><!--?實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)連接池的自動(dòng)化配置?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>?<!--?本示例,我們使用?MySQL?--><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.48</version></dependency><!--?方便等會(huì)寫(xiě)單元測(cè)試?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>-
無(wú)需主動(dòng)引入 HikariCP 的依賴(lài)。因?yàn)樵?Spring Boot 2.X 中,spring-boot-starter-jdbc?默認(rèn)引入?com.zaxxer.HikariCP?依賴(lài)。
2.2 應(yīng)用配置文件
在?application.yml?中,添加 HikariCP 配置,如下:
spring:#?datasource?數(shù)據(jù)源配置內(nèi)容,對(duì)應(yīng)?DataSourceProperties?配置屬性類(lèi)datasource:url:?jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?root?#?數(shù)據(jù)庫(kù)賬號(hào)password:?#?數(shù)據(jù)庫(kù)密碼#?HikariCP?自定義配置,對(duì)應(yīng)?HikariConfig?配置屬性類(lèi)hikari:minimum-idle:?10?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為 10?個(gè)。maximum-pool-size:?10?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 10?個(gè)。-
在?spring.datasource?配置項(xiàng)下,我們可以添加數(shù)據(jù)源的通用配置。
-
在?spring.datasource.hikari?配置項(xiàng)下,我們可以添加 HikariCP 連接池的自定義配置。然后?DataSourceConfiguration.Hikari?會(huì)自動(dòng)化配置 HikariCP 連接池。
HikariCP 更多配置項(xiàng),可以看看如下表格:s
FROM 《HikariCP 連接池及其在 Spring Boot 中的配置》
| autoCommit | 自動(dòng)提交從池中返回的連接 | true | true | - |
| connectionTimeout | 等待來(lái)自池的連接的最大毫秒數(shù) | SECONDS.toMillis(30) = 30000 | 30000 | 如果小于250毫秒,則被重置回30秒 |
| idleTimeout | 連接允許在池中閑置的最長(zhǎng)時(shí)間 | MINUTES.toMillis(10) = 600000 | 600000 | 如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,則會(huì)被重置為0(代表永遠(yuǎn)不會(huì)退出);如果idleTimeout!=0且小于10秒,則會(huì)被重置為10秒 |
| maxLifetime | 池中連接最長(zhǎng)生命周期 | MINUTES.toMillis(30) = 1800000 | 1800000 | 如果不等于0且小于30秒則會(huì)被重置回30分鐘 |
| connectionTestQuery | 如果您的驅(qū)動(dòng)程序支持JDBC4,我們強(qiáng)烈建議您不要設(shè)置此屬性 | null | null | - |
| minimumIdle | 池中維護(hù)的最小空閑連接數(shù) | -1 | 10 | minIdle<0或者minIdle>maxPoolSize,則被重置為maxPoolSize |
| maximumPoolSize | 池中最大連接數(shù),包括閑置和使用中的連接 | -1 | 10 | 如果maxPoolSize小于1,則會(huì)被重置。當(dāng)minIdle<=0被重置為DEFAULT_POOL_SIZE則為10;如果minIdle>0則重置為minIdle的值 |
| metricRegistry | 該屬性允許您指定一個(gè) Codahale / Dropwizard?MetricRegistry?的實(shí)例,供池使用以記錄各種指標(biāo) | null | null | - |
| healthCheckRegistry | 該屬性允許您指定池使用的Codahale / Dropwizard HealthCheckRegistry的實(shí)例來(lái)報(bào)告當(dāng)前健康信息 | null | null | - |
| poolName | 連接池的用戶(hù)定義名稱(chēng),主要出現(xiàn)在日志記錄和JMX管理控制臺(tái)中以識(shí)別池和池配置 | null | HikariPool-1 | - |
| initializationFailTimeout | 如果池?zé)o法成功初始化連接,則此屬性控制池是否將?fail fast | 1 | 1 | - |
| isolateInternalQueries | 是否在其自己的事務(wù)中隔離內(nèi)部池查詢(xún),例如連接活動(dòng)測(cè)試 | false | false | - |
| allowPoolSuspension | 控制池是否可以通過(guò)JMX暫停和恢復(fù) | false | false | - |
| readOnly | 從池中獲取的連接是否默認(rèn)處于只讀模式 | false | false | - |
| registerMbeans | 是否注冊(cè)JMX管理Bean(MBeans) | false | false | - |
| catalog | 為支持?catalog?概念的數(shù)據(jù)庫(kù)設(shè)置默認(rèn)?catalog | driver default | null | - |
| connectionInitSql | 該屬性設(shè)置一個(gè)SQL語(yǔ)句,在將每個(gè)新連接創(chuàng)建后,將其添加到池中之前執(zhí)行該語(yǔ)句。 | null | null | - |
| driverClassName | HikariCP將嘗試通過(guò)僅基于jdbcUrl的DriverManager解析驅(qū)動(dòng)程序,但對(duì)于一些較舊的驅(qū)動(dòng)程序,還必須指定driverClassName | null | null | - |
| transactionIsolation | 控制從池返回的連接的默認(rèn)事務(wù)隔離級(jí)別 | null | null | - |
| validationTimeout | 連接將被測(cè)試活動(dòng)的最大時(shí)間量 | SECONDS.toMillis(5) = 5000 | 5000 | 如果小于250毫秒,則會(huì)被重置回5秒 |
| leakDetectionThreshold | 記錄消息之前連接可能離開(kāi)池的時(shí)間量,表示可能的連接泄漏 | 0 | 0 | 如果大于0且不是單元測(cè)試,則進(jìn)一步判斷:(leakDetectionThreshold < SECONDS.toMillis(2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0),會(huì)被重置為0 . 即如果要生效則必須>0,而且不能小于2秒,而且當(dāng)maxLifetime > 0時(shí)不能大于maxLifetime |
| dataSource | 這個(gè)屬性允許你直接設(shè)置數(shù)據(jù)源的實(shí)例被池包裝,而不是讓HikariCP通過(guò)反射來(lái)構(gòu)造它 | null | null | - |
| schema | 該屬性為支持模式概念的數(shù)據(jù)庫(kù)設(shè)置默認(rèn)模式 | driver default | null | - |
| threadFactory | 此屬性允許您設(shè)置將用于創(chuàng)建池使用的所有線(xiàn)程的java.util.concurrent.ThreadFactory的實(shí)例。 | null | null | - |
| scheduledExecutor | 此屬性允許您設(shè)置將用于各種內(nèi)部計(jì)劃任務(wù)的java.util.concurrent.ScheduledExecutorService實(shí)例 | null | null | - |
2.3 Application
創(chuàng)建?Application.java?類(lèi),配置?@SpringBootApplication?注解即可。代碼如下:
//?Application.java@SpringBootApplication public?class?Application?implements?CommandLineRunner?{private?Logger?logger?=?LoggerFactory.getLogger(Application.class);@Autowiredprivate?DataSource?dataSource;public?static?void?main(String[]?args)?{//?啟動(dòng)?Spring?Boot?應(yīng)用SpringApplication.run(Application.class,?args);}@Overridepublic?void?run(String...?args)?{try?(Connection?conn?=?dataSource.getConnection())?{//?這里,可以做點(diǎn)什么logger.info("[run][獲得連接:{}]",?conn);}?catch?(SQLException?e)?{throw?new?RuntimeException(e);}}}通過(guò)實(shí)現(xiàn) CommandLineRunner 接口,應(yīng)用啟動(dòng)完成后,回調(diào)?#run(String... args)?方法,輸出下 Connection 信息。執(zhí)行日志如下:
2019-11-12?11:15:32.303??INFO?41198?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-1?-?Starting... 2019-11-12?11:15:32.472??INFO?41198?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-1?-?Start?completed. 2019-11-12?11:15:32.473??INFO?41198?---?[?????????? main] c.i.s.lab19.datasourcepool.Application ??:?[run][獲得連接:HikariProxyConnection@1561745898?wrapping?com.mysql.jdbc.JDBC4Connection@793138bd]-
可以看到,HikariDataSource 成功初始化。
3. HikariCP 多數(shù)據(jù)源
示例代碼對(duì)應(yīng)倉(cāng)庫(kù):lab-19-datasource-pool-hikaricp-multiple 。
在本小節(jié),我們會(huì)使用配置兩個(gè)數(shù)據(jù)源的 HikariCP 連接池。
3.1 引入依賴(lài)
和 「2.1 引入依賴(lài)」 是一致。
3.2 應(yīng)用配置文件
在?application.yml?中,添加 HikariCP 配置,如下:
spring:#?datasource?數(shù)據(jù)源配置內(nèi)容datasource:#?訂單數(shù)據(jù)源配置orders:url:?jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?rootpassword:#?HikariCP?自定義配置,對(duì)應(yīng)?HikariConfig?配置屬性類(lèi)hikari:minimum-idle:?20?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為 10?個(gè)。maximum-pool-size:?20?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 10?個(gè)。#?用戶(hù)數(shù)據(jù)源配置users:url:?jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?rootpassword:#?HikariCP?自定義配置,對(duì)應(yīng)?HikariConfig?配置屬性類(lèi)hikari:minimum-idle:?15?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為 10?個(gè)。maximum-pool-size:?15?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 10?個(gè)。-
我們?cè)?spring.datasource?配置項(xiàng)下,定義了?orders?和?users?兩個(gè)數(shù)據(jù)源的配置。而每個(gè)數(shù)據(jù)源的配置,和我們?cè)?「2.2 應(yīng)用配置文件」 是一致的。
3.3 數(shù)據(jù)源配置類(lèi)
3.3.1 錯(cuò)誤的示例
在網(wǎng)上,我們會(huì)看到這樣配置多個(gè)數(shù)據(jù)源的配置類(lèi)。代碼如下:
@Bean(name?=?"ordersDataSource") @ConfigurationProperties(prefix?=?"spring.datasource.orders") public?DataSource?ordersDataSource()?{return?DataSourceBuilder.create().build(); }@Bean(name?=?"usersDataSource") @ConfigurationProperties(prefix?=?"spring.datasource.users") public?DataSource?ordersDataSource()?{return?DataSourceBuilder.create().build(); }-
實(shí)際上,這樣做的話(huà),在部分場(chǎng)景下,會(huì)存在問(wèn)題,這是為什么呢?
-
我們先來(lái)理解這段程序的用途。以?#ordersDataSource()?方法為例子:
-
DataSourceBuilder.create().build()?代碼段,會(huì)創(chuàng)建一個(gè) DataSource 數(shù)據(jù)源。
-
搭配上?@Bean(name = "ordersDataSource")?注解,會(huì)創(chuàng)建一個(gè)名字為?"ordersDataSource"?的 DataSource Bean 。這里,我們使用 HikariCP ,所以返回的是 HikariDataSource Bean 。
-
@ConfigurationProperties(prefix = "spring.datasource.orders")?注解,會(huì)將?"spring.datasource.orders"?配置項(xiàng),逐個(gè)屬性賦值給 DataSource Bean 。
-
-
看起來(lái)貌似沒(méi)問(wèn)題,但是如果每個(gè)數(shù)據(jù)源如果有 HikariCP 的?"hikari"?自定義配置項(xiàng)時(shí),它的自定義配置項(xiàng)無(wú)法設(shè)置到 HikariDataSource Bean 中。因?yàn)?#xff0c;"spring.datasource.orders.hikari"?是?"spring.datasource.orders"?的第二層屬性。而 HikariDataSource 的配置屬性在第一層,這就導(dǎo)致無(wú)法正確的設(shè)置。
雖然存在該問(wèn)題,但是大多數(shù)項(xiàng)目,我們并不會(huì)自定義 HikariCP 的?"hikari"?配置項(xiàng),所以這個(gè)問(wèn)題就偷偷藏起來(lái),**“不存在”**了。
3.3.2 正確的示例
當(dāng)然,作為入門(mén)的示例,艿艿還是希望提供正確的做法。
在?cn.iocoder.springboot.lab19.datasourcepool.config?包路徑下,我們會(huì)創(chuàng)建 DataSourceConfig 配置類(lèi)。代碼如下:
//?DataSourceConfig.java@Configuration public?class?DataSourceConfig?{/***?創(chuàng)建?orders?數(shù)據(jù)源的配置對(duì)象*/@Primary@Bean(name?=?"ordersDataSourceProperties")@ConfigurationProperties(prefix?=?"spring.datasource.orders")?//?讀取?spring.datasource.orders?配置到?DataSourceProperties?對(duì)象public?DataSourceProperties?ordersDataSourceProperties()?{return?new?DataSourceProperties();}/***?創(chuàng)建?orders?數(shù)據(jù)源*/@Bean(name?=?"ordersDataSource")@ConfigurationProperties(prefix?=?"spring.datasource.orders.hikari")?//?讀取?spring.datasource.orders?配置到?HikariDataSource?對(duì)象public?DataSource?ordersDataSource()?{//?<1.1>?獲得?DataSourceProperties?對(duì)象DataSourceProperties?properties?=??this.ordersDataSourceProperties();//?<1.2>?創(chuàng)建?HikariDataSource?對(duì)象return?createHikariDataSource(properties);}/***?創(chuàng)建?users?數(shù)據(jù)源的配置對(duì)象*/@Bean(name?=?"usersDataSourceProperties")@ConfigurationProperties(prefix?=?"spring.datasource.users")?//?讀取?spring.datasource.users?配置到?DataSourceProperties?對(duì)象public?DataSourceProperties?usersDataSourceProperties()?{return?new?DataSourceProperties();}/***?創(chuàng)建?users?數(shù)據(jù)源*/@Bean(name?=?"usersDataSource")@ConfigurationProperties(prefix?=?"spring.datasource.users.hikari")public?DataSource?usersDataSource()?{//?獲得?DataSourceProperties?對(duì)象DataSourceProperties?properties?=??this.usersDataSourceProperties();//?創(chuàng)建?HikariDataSource?對(duì)象return?createHikariDataSource(properties);}private?static?HikariDataSource?createHikariDataSource(DataSourceProperties?properties)?{//?創(chuàng)建?HikariDataSource?對(duì)象HikariDataSource?dataSource?=?properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();//?設(shè)置線(xiàn)程池名if?(StringUtils.hasText(properties.getName()))?{dataSource.setPoolName(properties.getName());}return?dataSource;}}-
這塊代碼,我們是參考 Spring Boot?DataSourceConfiguration.Hikari?配置類(lèi)來(lái)實(shí)現(xiàn)的。
-
#ordersDataSourceProperties()?方法,創(chuàng)建?"orders"?數(shù)據(jù)源的 DataSourceProperties 配置對(duì)象。
-
@Primary?注解,保證項(xiàng)目中有一個(gè)主的 DataSourceProperties Bean 。
-
new DataSourceProperties()?代碼段,會(huì)創(chuàng)建一個(gè) DataSourceProperties 數(shù)據(jù)源的配置對(duì)象。
-
搭配上?@Bean(name = "ordersDataSourceProperties")?注解,會(huì)創(chuàng)建一個(gè)名字為?"ordersDataSourceProperties"?的 DataSourceProperties Bean 。
-
@ConfigurationProperties(prefix = "spring.datasource.orders")?注解,會(huì)將?"spring.datasource.orders"?配置項(xiàng),逐個(gè)屬性賦值給 DataSourceProperties Bean 。
-
-
#ordersDataSource()?方法,創(chuàng)建?orders?數(shù)據(jù)源。
-
<1.1>?處,調(diào)用?#ordersDataSourceProperties()?方法,獲得?orders?數(shù)據(jù)源的 DataSourceProperties 。
-
<1.2>?處,調(diào)用?#createHikariDataSource(DataSourceProperties properties)?方法,創(chuàng)建 HikariDataSource 對(duì)象。這樣,"spring.datasource.orders"?配置項(xiàng),逐個(gè)屬性賦值給 HikariDataSource Bean 。
-
搭配上?@Bean(name = "ordersDataSource")?注解,會(huì)創(chuàng)建一個(gè)名字為?"ordersDataSource"?的 HikariDataSource Bean 。
-
@ConfigurationProperties(prefix = "spring.datasource.orders.hikari")?注解,會(huì)將 HikariCP 的?"spring.datasource.orders.hikari"?自定義配置項(xiàng),逐個(gè)屬性賦值給 HikariDataSource Bean 。
-
-
users?數(shù)據(jù)源的配置,同上,就不重復(fù)解釋了。
3.4 Application
創(chuàng)建?Application.java?類(lèi),配置?@SpringBootApplication?注解即可。代碼如下:
//?Application.java@SpringBootApplication public?class?Application?implements?CommandLineRunner?{private?Logger?logger?=?LoggerFactory.getLogger(Application.class);@Resource(name?=?"ordersDataSource")private?DataSource?ordersDataSource;@Resource(name?=?"usersDataSource")private?DataSource?usersDataSource;public?static?void?main(String[]?args)?{//?啟動(dòng)?Spring?Boot?應(yīng)用SpringApplication.run(Application.class,?args);}@Overridepublic?void?run(String...?args)?{//?orders?數(shù)據(jù)源try?(Connection?conn?=?ordersDataSource.getConnection())?{//?這里,可以做點(diǎn)什么logger.info("[run][ordersDataSource 獲得連接:{}]",?conn);}?catch?(SQLException?e)?{throw?new?RuntimeException(e);}//?users?數(shù)據(jù)源try?(Connection?conn?=?usersDataSource.getConnection())?{//?這里,可以做點(diǎn)什么logger.info("[run][usersDataSource 獲得連接:{}]",?conn);}?catch?(SQLException?e)?{throw?new?RuntimeException(e);}}}執(zhí)行日志如下:
2019-11-12?15:30:35.060??INFO?45868?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-1?-?Starting... 2019-11-12?15:30:35.365??INFO?45868?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-1?-?Start?completed. 2019-11-12?15:30:35.367??INFO?45868?---?[?????????? main] c.i.s.lab19.datasourcepool.Application ??:?[run][ordersDataSource 獲得連接:HikariProxyConnection@1041547629?wrapping?com.mysql.jdbc.JDBC4Connection@3c989952] 2019-11-12?15:30:35.371??INFO?45868?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-2?-?Starting... 2019-11-12?15:30:35.376??INFO?45868?---?[???????????main]?com.zaxxer.hikari.HikariDataSource???????:?HikariPool-2?-?Start?completed. 2019-11-12?15:30:35.376??INFO?45868?---?[?????????? main] c.i.s.lab19.datasourcepool.Application ??:?[run][usersDataSource 獲得連接:HikariProxyConnection@795748540?wrapping?com.mysql.jdbc.JDBC4Connection@7c098bb3]-
可以看到,兩個(gè) HikariDataSource 成功初始化。
多數(shù)據(jù)源和 JPA、MyBatis、JdbcTemplate 的集成,可以看看 《芋道 Spring Boot 多數(shù)據(jù)源(讀寫(xiě)分離)入門(mén)》 文章。
4. Druid 單數(shù)據(jù)源
示例代碼對(duì)應(yīng)倉(cāng)庫(kù):lab-19-datasource-pool-druid-single 。
在本小節(jié),我們會(huì)使用配置一個(gè)數(shù)據(jù)源的 Druid 連接池。并簡(jiǎn)單看看 Druid 的監(jiān)控功能。
艿艿:推薦入門(mén)后,可以看看 Druid 的文檔:https://github.com/alibaba/druid/wiki/ 。
4.1 引入依賴(lài)
在?pom.xml?文件中,引入相關(guān)依賴(lài)。
<?xml?version="1.0"?encoding="UTF-8"?> <project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/>?<!--?lookup?parent?from?repository?--></parent><modelVersion>4.0.0</modelVersion><artifactId>lab-19-datasource-pool-druid-single</artifactId><dependencies><!--?保證?Spring?JDBC?的依賴(lài)健全?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!--?實(shí)現(xiàn)對(duì)?Druid?連接池的自動(dòng)化配置?--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.21</version></dependency><dependency>?<!--?本示例,我們使用?MySQL?--><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.48</version></dependency><!--?實(shí)現(xiàn)對(duì)?Spring?MVC?的自動(dòng)化配置,因?yàn)槲覀冃枰纯?Druid?的監(jiān)控功能?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--?方便等會(huì)寫(xiě)單元測(cè)試?--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>具體每個(gè)依賴(lài)的作用,胖友自己認(rèn)真看下艿艿添加的所有注釋噢。S
4.2 應(yīng)用配置文件
在?application.yml?中,添加 Druid 配置,如下:
spring:#?datasource?數(shù)據(jù)源配置內(nèi)容,對(duì)應(yīng)?DataSourceProperties?配置屬性類(lèi)datasource:url:?jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?root?#?數(shù)據(jù)庫(kù)賬號(hào)password:?#?數(shù)據(jù)庫(kù)密碼type:?com.alibaba.druid.pool.DruidDataSource?#?設(shè)置類(lèi)型為?DruidDataSource#?Druid?自定義配置,對(duì)應(yīng)?DruidDataSource?中的?setting?方法的屬性druid:min-idle:?0?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為?0?個(gè)。max-active:?20?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 8 個(gè)。filter:stat:?#?配置?StatFilter?,對(duì)應(yīng)文檔?https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilterlog-slow-sql:?true?#?開(kāi)啟慢查詢(xún)記錄slow-sql-millis:?5000?#?慢 SQL 的標(biāo)準(zhǔn),單位:毫秒stat-view-servlet:?#?配置?StatViewServlet?,對(duì)應(yīng)文檔?https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AEenabled:?true?#?是否開(kāi)啟?StatViewServletlogin-username:?yudaoyuanma?#?賬號(hào)login-password:?javaniubi?#?密碼-
spring.datasource?配置項(xiàng),設(shè)置 Spring 數(shù)據(jù)源的通用配置。其中,spring.datasource.type?配置項(xiàng),需要主動(dòng)設(shè)置使用 DruidDataSource 。因?yàn)槟J(rèn)情況下,spring-boot-starter-jdbc?的 DataSourceBuilder 會(huì)按照?DATA_SOURCE_TYPE_NAMES?的順序,嘗試推斷數(shù)據(jù)源的類(lèi)型。
-
spring.datasource.druid?配置項(xiàng),設(shè)置 Druid 連接池的自定義配置。然后 DruidDataSourceAutoConfigure 會(huì)自動(dòng)化配置 Druid 連接池。
-
在 《Druid —— 配置屬性》 和 《DruidDataSource 配置屬性列表》 下,提供了各種 Druid 的配置項(xiàng),胖友可以自己看看。
-
filter.stat?配置項(xiàng),我們配置了 Druid StatFilter ,用于統(tǒng)計(jì)監(jiān)控信息。對(duì)應(yīng)文檔 《Druid —— 配置_StatFilter》 。要注意,StatFilter 并不是我們說(shuō)的?javax.servlet.Filter?,而是 Druid 提供的 Filter 拓展機(jī)制。
-
filter.stat-view-servlet?配置項(xiàng),我們配置了 Druid StatViewServlet ,用于提供監(jiān)控信息的展示的 html 頁(yè)面和?JSON API?。對(duì)應(yīng)文檔 《Druid —— 配置_StatViewServlet 配置》 。StatViewServlet 就是我們說(shuō)的?javax.servlet.Filter?。
-
4.3 Application
創(chuàng)建?Application.java?類(lèi),配置?@SpringBootApplication?注解即可。代碼如下:
@SpringBootApplication public?class?Application?implements?CommandLineRunner?{private?Logger?logger?=?LoggerFactory.getLogger(Application.class);@Autowiredprivate?DataSource?dataSource;public?static?void?main(String[]?args)?{//?啟動(dòng)?Spring?Boot?應(yīng)用SpringApplication.run(Application.class,?args);}@Overridepublic?void?run(String...?args)?{logger.info("[run][獲得數(shù)據(jù)源:{}]",?dataSource.getClass());}}執(zhí)行日志如下:
2019-11-12?19:34:12.079??INFO?48359?---?[???????????main]?c.a.d.s.b.a.DruidDataSourceAutoConfigure?:?Init?DruidDataSource 2019-11-12?19:34:12.156??INFO?48359?---?[???????????main]?com.alibaba.druid.pool.DruidDataSource???:?{dataSource-1}?inited2019-11-12?19:34:12.560??INFO?48359?---?[?????????? main] c.i.s.lab19.datasourcepool.Application ??:?[run][獲得數(shù)據(jù)源:class?com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]-
可以看到,DruidDataSource 成功初始化。
4.4 監(jiān)控功能
因?yàn)槲覀冊(cè)?「4.2 應(yīng)用配置中」 中,做了如下操作:
-
通過(guò)?spring.datasource.filter.stat?配置了 StatFilter ,統(tǒng)計(jì)監(jiān)控信息。
-
通過(guò)?spring.datasource.filter.stat-view-servlet?配置了 StatViewServlet ,提供監(jiān)控信息的展示的 html 頁(yè)面和 JSON API 。
所以我們?cè)趩?dòng)項(xiàng)目后,訪(fǎng)問(wèn)?http://127.0.0.1:8080/druid?地址,可以看到監(jiān)控 html 頁(yè)面。如下圖所示:
-
在界面的頂部,提供了數(shù)據(jù)源、SQL 監(jiān)控、SQL 防火墻等等功能。
-
每個(gè)界面上,可以通過(guò) View JSON API 獲得數(shù)據(jù)的來(lái)源。同時(shí),我們可以在 JSON API(?http://127.0.0.1:8080/druid/api.html?) 菜單對(duì)應(yīng)的界面中,看到 StatViewServlet 內(nèi)置的監(jiān)控信息的 JSON API 列表。
-
因?yàn)楸O(jiān)控信息是存儲(chǔ)在 JVM 內(nèi)存中,在 JVM 進(jìn)程重啟時(shí),信息將會(huì)丟失。如果我們希望持久化到 MySQL、Elasticsearch、HBase 等存儲(chǔ)器中,可以通過(guò) StatViewServlet 提供的 JSON API 接口,采集監(jiān)控信息。另外,有個(gè) druid-aggregated-monitor 開(kāi)源項(xiàng)目,提供了 集中監(jiān)控分布式服務(wù)中的 Druid 連接池的方案和思路。
-
如果 StatViewServlet 提供的 JSON API 接口,無(wú)法滿(mǎn)足我們的訴求,我們可以通過(guò)自定義 API 接口,使用 DruidStatManagerFacade 獲得監(jiān)控信息。使用示例 DruidStatController 代碼如下:
//?DruidStatController.java@RestController public?class?DruidStatController?{@GetMapping("/monitor/druid/stat")@Deprecatedpublic?Object?druidStat(){//?`DruidStatManagerFacade#getDataSourceStatDataList()`?方法,可以獲取所有數(shù)據(jù)源的監(jiān)控?cái)?shù)據(jù)。//?除此之外,DruidStatManagerFacade 還提供了一些其他方法,你可以按需選擇使用。return?DruidStatManagerFacade.getInstance().getDataSourceStatDataList();}}-
當(dāng)然,絕大多數(shù)情況下,我們并不需要做這方面的拓展。
-
5. Druid 多數(shù)據(jù)源
示例代碼對(duì)應(yīng)倉(cāng)庫(kù):lab-19-datasource-pool-druid-multiple 。
在本小節(jié),我們會(huì)使用配置兩個(gè)數(shù)據(jù)源的 Druid 連接池。
5.1 引入依賴(lài)
和 「4.1 引入依賴(lài)」 是一致。
5.2 應(yīng)用配置
在?application.yml?中,添加 Druid 配置,如下:
spring:#?datasource?數(shù)據(jù)源配置內(nèi)容datasource:#?訂單數(shù)據(jù)源配置orders:url:?jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?rootpassword:type:?com.alibaba.druid.pool.DruidDataSource?#?設(shè)置類(lèi)型為?DruidDataSource#?Druid?自定義配置,對(duì)應(yīng)?DruidDataSource?中的?setting?方法的屬性min-idle:?0?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為?0?個(gè)。max-active:?20?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 8 個(gè)。#?用戶(hù)數(shù)據(jù)源配置users:url:?jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8driver-class-name:?com.mysql.jdbc.Driverusername:?rootpassword:type:?com.alibaba.druid.pool.DruidDataSource?#?設(shè)置類(lèi)型為?DruidDataSource#?Druid?自定義配置,對(duì)應(yīng)?DruidDataSource?中的?setting?方法的屬性min-idle:?0?#?池中維護(hù)的最小空閑連接數(shù),默認(rèn)為?0?個(gè)。max-active:?20?#?池中最大連接數(shù),包括閑置和使用中的連接,默認(rèn)為 8 個(gè)。#?Druid?自定已配置druid:#?過(guò)濾器配置filter:stat:?#?配置?StatFilter?,對(duì)應(yīng)文檔?https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilterlog-slow-sql:?true?#?開(kāi)啟慢查詢(xún)記錄slow-sql-millis:?5000?#?慢 SQL 的標(biāo)準(zhǔn),單位:毫秒#?StatViewServlet?配置stat-view-servlet:?#?配置?StatViewServlet?,對(duì)應(yīng)文檔?https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AEenabled:?true?#?是否開(kāi)啟?StatViewServletlogin-username:?yudaoyuanma?#?賬號(hào)login-password:?javaniubi?#?密碼-
不同于我們?cè)?「3.2 應(yīng)用配置文件」 中,我們將 Druid 的自定義配置,和?url、driver-class-name?等數(shù)據(jù)源的通用配置放在同一級(jí),這樣后續(xù)我們只需要使用?@ConfigurationProperties(prefix = "spring.datasource.orders")?的方式,就能完成 DruidDataSource 的配置屬性設(shè)置。
-
在?spring.datasource.druid?配置項(xiàng)下,我們還是配置了?filter.stat?和?stat-view-servlet?配置項(xiàng),用于 Druid 監(jiān)控功能。
5.3 數(shù)據(jù)源配置類(lèi)
在?cn.iocoder.springboot.lab19.datasourcepool.config?包路徑下,我們會(huì)創(chuàng)建 DataSourceConfig 配置類(lèi)。代碼如下:
//?DataSourceConfig.java@Configuration public?class?DataSourceConfig?{/***?創(chuàng)建?orders?數(shù)據(jù)源*/@Primary@Bean(name?=?"ordersDataSource")@ConfigurationProperties(prefix?=?"spring.datasource.orders")?//?讀取?spring.datasource.orders?配置到?HikariDataSource?對(duì)象public?DataSource?ordersDataSource()?{return?DruidDataSourceBuilder.create().build();}/***?創(chuàng)建?users?數(shù)據(jù)源*/@Bean(name?=?"usersDataSource")@ConfigurationProperties(prefix?=?"spring.datasource.users")public?DataSource?usersDataSource()?{return?DruidDataSourceBuilder.create().build();}}-
因?yàn)槲覀冊(cè)?「5.2 應(yīng)用配置」 中,將 Druid 自定義的配置項(xiàng),和數(shù)據(jù)源的通用配置放在了同一級(jí),所以我們只需使用?@ConfigurationProperties(prefix = "spring.datasource.orders")?這樣的方式即可。
-
當(dāng)然,「3.3.2 正確的示例」 也是可以這么做的。實(shí)際情況下,比較推薦本小節(jié)的方式。
5.4 Application
創(chuàng)建?Application.java?類(lèi),配置?@SpringBootApplication?注解即可。代碼如下:
//?Application.java@SpringBootApplication public?class?Application?implements?CommandLineRunner?{private?Logger?logger?=?LoggerFactory.getLogger(Application.class);@Resource(name?=?"ordersDataSource")private?DataSource?ordersDataSource;@Resource(name?=?"usersDataSource")private?DataSource?usersDataSource;public?static?void?main(String[]?args)?{//?啟動(dòng)?Spring?Boot?應(yīng)用SpringApplication.run(Application.class,?args);}@Overridepublic?void?run(String...?args)?{//?orders?數(shù)據(jù)源logger.info("[run][獲得數(shù)據(jù)源:{}]",?ordersDataSource.getClass());//?users?數(shù)據(jù)源logger.info("[run][獲得數(shù)據(jù)源:{}]",?usersDataSource.getClass());}}執(zhí)行日志如下:
2019-11-12?21:39:24.063??INFO?49670?---?[?????????? main] c.i.s.lab19.datasourcepool.Application ??:?[run][獲得數(shù)據(jù)源:class?com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper] 2019-11-12?21:39:24.064??INFO?49670?---?[???????????main]?c.i.s.lab19.datasourcepool.Application???:?[run][獲得數(shù)據(jù)源:class?com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]-
可以看到,兩個(gè) DruidDataSource 成功初始化。
5.5 監(jiān)控功能
和 「4.4 監(jiān)控功能」 一致。
不過(guò)呢,我們?cè)诒O(jiān)控頁(yè)面上,可以看到兩個(gè) Druid 數(shù)據(jù)庫(kù)連接池。
666. 彩蛋
艿艿:咳咳咳,瞎嗶嗶了一些內(nèi)容,可以選擇不看。😜
艿艿在星球里,做了一波目前在使用的連接池的調(diào)查,大概比例是 Druid : HikariCP 為 2:1 左右。猜測(cè)隨著 Spring Boot 2.X 逐步普及之后,HikariCP 有一定幾率反超 Druid 。
雖然說(shuō),HikariCP 沒(méi)有直接提供監(jiān)控功能,但是可以使用 Prometheus 采集 Spring Boot Metrics 的數(shù)據(jù),后續(xù)使用 Grafana 制作儀表盤(pán)。目前,已經(jīng)有 Spring Boot HikariCP / JDBC 可以直接使用。具體怎么做,胖友可以看看 《Spring Boot 中使用 HikariCP 連接池》 文章。
Druid 的 Issues 3047 中,也有人提出,是否能夠提供 Druid 接入 Prometheus 統(tǒng)一監(jiān)控的訴求。Druid 目前暫時(shí)不支持,不過(guò)有聰慧的胖友,提出了使用 Prometheus jmx_exporter 的方式,將 Druid 實(shí)現(xiàn)的 JMX 格式的指標(biāo)暴露出來(lái),提供給 Prometheus 采集監(jiān)控信息。
在編寫(xiě)本文的過(guò)程中,無(wú)意中看到 Druid 文檔中提到,曾經(jīng)想試驗(yàn)性的提供 分庫(kù)分表 的功能,而艿艿的記憶中,Sharding-JDBC 曾經(jīng)也想開(kāi)發(fā)數(shù)據(jù)庫(kù)連接池的功能。大體在 DataSource 數(shù)據(jù)源上做拓展的中間件,可能都不甘于僅僅只覆蓋一塊需求,而是希望成為一站式的數(shù)據(jù)庫(kù)中間件。立個(gè) Flag ,ShardingSphere 可能會(huì)提供數(shù)據(jù)庫(kù)連接池的組件。
旁白君:Sharding-JDBC 是 ShardingSphere 在 JDBC 層面提供的分庫(kù)分表組件。當(dāng)然,不僅僅提供分庫(kù)分表的功能,也提供讀寫(xiě)分離、數(shù)據(jù)脫敏、分布式事務(wù)等等功能。
如果胖友工作的比較早,一定還接觸過(guò)其它連接池。例如說(shuō),c3p0、dbcp、BoneCP 等等。數(shù)據(jù)庫(kù)連接池的發(fā)展過(guò)程,是個(gè)非常有意思的歷史。感興趣的胖友,可以看看 《大話(huà)數(shù)據(jù)庫(kù)連接池簡(jiǎn)史,你都用過(guò)幾個(gè)?》 一文,江湖味十足~
可能胖友會(huì)比較糾結(jié),是否要去自定義連接池的配置呢?一般情況下,默認(rèn)的配置基本能夠滿(mǎn)足項(xiàng)目的基本要求,不需要特別刻意去修改。當(dāng)然,這里推薦看兩篇文章:
-
《DruidDataSource 配置》 ,Druid 官方提供了通用的配置。
-
《Druid 連接池推薦配置》 ,某公司的內(nèi)部實(shí)踐。
總結(jié)
以上是生活随笔為你收集整理的Spring Boot 数据库连接池入门的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java项目构建基础的三个统一,太厉害了
- 下一篇: Spring Boot 多模块项目实践(