細數(shù) SpringBoot 中的連接池
這是Java極客技術(shù)的第312篇原創(chuàng)文章
hello~各位讀者新年好,我是鴨血粉絲(大家會親切的喊我「阿粉」),是一位喜歡吃鴨血粉絲的程序員!
回想起前幾天在部署springboot項目到正線時,線上環(huán)境要求jdk7,可項目是基于jdk8開發(fā)的,springboot也是用的springboot2以上的版本,可以說縫縫補補一整天才搞好能滿足線上環(huán)境的代碼,搞完后當然需要小小的了解一下背后的秘密。
好了,話不多說,我們直接進入正題。
其實切換還不算太麻煩,坑就坑在SpringBoot2切換到SpringBoot1后,默認使用的連接池發(fā)生了變化,之前做的壓力測試又重新搞了一遍
接下里我們就一起來檢驗下SpringBoot2和SpringBoot1使用的默認數(shù)據(jù)源吧!
一、SpringBoot2的HikariCP首先在pom文件中需要引入的依賴包:
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.0.4.RELEASE</version>
- </parent>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- <mybatis.spring.boot.version>1.3.1</mybatis.spring.boot.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>${mybatis.spring.boot.version}</version>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
- </dependencies>
其次在配置文件中需要定義如下屬性(不定義時會自動使用默認值)
- # spring的相關(guān)配置
- spring:
- application:
- name: HikariCP測試
- # 數(shù)據(jù)源的配置
- datasource:
- # 連接池的配置
- type: com.zaxxer.hikari.HikariDataSource
- hikari:
- minimum-idle: 5
- maximum-pool-size: 15
- connection-test-query: SELECT 1
- max-lifetime: 1800000
- connection-timeout: 30000
- pool-name: DatebookHikariCP
配置好后,啟動成功時你能看到類似這樣子的打印信息:
- 2020-01-16 16:23:12.911 INFO 9996 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
- 2020-01-16 16:23:12.913 INFO 9996 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
- 2020-01-16 16:23:12.924 INFO 9996 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
- 2020-01-16 16:23:12.994 INFO 9996 --- [ main ] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 18001 (http) with context path ''
- 2020-01-16 16:23:13.002 INFO 9996 --- [ main ] c.j.mmzsblog.DatasourceTestApplication : Started DatasourceTestApplication in 6.724 seconds (JVM running for 8.883)
其中第3行[com.zaxxer.hikari:name=dataSource,type=HikariDataSource]這部分就點明了使用的連接池類型
二、SpringBoot1的tomcat-jdbc降低版本后,我沒有看到上面的信息打印,一時差點不知道使用了什么連接池,不過網(wǎng)上都說是tomcat-jdbc;但是相信眼見為實的我,肯定要在哪里打印一下才放心,于是乎,我進行了如下操作:
搞了一個controller來簡單的打印一下連接池的信息
- @RestController
- public class testController {
- @Resource
- private DataSource dataSource;
- @GetMapping("/query")
- public void query(){
- System.out.println("查詢到的數(shù)據(jù)源連接池信息是:"+dataSource);
- System.out.println("查詢到的數(shù)據(jù)源連接池類型是:"+dataSource.getClass());
- System.out.println("查詢到的數(shù)據(jù)源連接池名字是:"+dataSource.getPoolProperties().getName());
- }
- }
然后我就看到了如下的打印信息,果真是用的tomcat-jdbc
- 查詢到的數(shù)據(jù)源連接池信息是:org.apache.tomcat.jdbc.pool.DataSource@181d8899{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=100; minIdle=10; initialSize=10; maxWait=30000; testOnBorrow=true; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=********; url=jdbc:mysql://localhost:3306/xxxxxx; username=xxxx; validationQuery=SELECT 1; validationQueryTimeout=-1; validatorClassName=null; validationInterval=3000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; ignoreExceptionOnPreLoad=false; useStatementFacade=true; }
- 查詢到的數(shù)據(jù)源連接池類型是:class org.apache.tomcat.jdbc.pool.DataSource
- 查詢到的數(shù)據(jù)源連接池名字是:Tomcat Connection Pool[1-1715657818]
其實,我們從pom文件也能看出其中的門道:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency>
依賴文件中的這一個依賴其實就是表明了SpringBoot1使用的是tomcat-jdbc連接池。
哎,現(xiàn)在才知道SpringBoot2.0和SpringBoot1.0版本使用的默認數(shù)據(jù)庫是不一樣的。
現(xiàn)在原因是找到了,可是如何解決呢?要不然把SpringBoot1版本的默認連接池修改成和SpringBoot2版本的一樣。好,有了想法,那就開干。
其實,在SpringBoot1的版本也是可以使用HikariCP連接池的,操作就是:
首先引入默認配置的數(shù)據(jù)源處排除掉tomcat-jdbc
- <!--配置默認數(shù)據(jù)源 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- <exclusions>
- <!-- 排除默認的tomcat-jdbc數(shù)據(jù)源 -->
- <exclusion>
- <groupId>org.apache</groupId>
- <artifactId>tomcat-jdbc</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- 引用SpringBoot2默認的HikariCP數(shù)據(jù)源 -->
- <dependency>
- <groupId>com.zaxxer</groupId>
- <artifactId>HikariCP</artifactId>
- <version>3.3.1</version>
- </dependency>
再在.yml文件中配置HikariCP數(shù)據(jù)源的相關(guān)信息
- # spring的相關(guān)配置
- spring:
- # 數(shù)據(jù)源的配置
- datasource:
- # 連接池的配置
- type: com.zaxxer.hikari.HikariDataSource
- hikari:
- minimum-idle: 5
- maximum-pool-size: 15
- connection-test-query: SELECT 1
- max-lifetime: 1800000
- connection-timeout: 30000
為什么說我此處要將數(shù)據(jù)源切換成SpringBoot2.0使用的默認數(shù)據(jù)源呢?因為使用SpringBoot1.0的tomcat-jdbc數(shù)據(jù)源我怕壓力測試出來達不到要求,為了不給測試增加工作壓力(阿粉我就是這么好的一個人)
不過這樣做肯定也是有好處的。好處就在于HikariCP那迷人的優(yōu)勢:
1、字節(jié)碼級別優(yōu)化(很多方法通過JavaAssist生成)
2、大量小改進
用FastStatementList代替ArrayList
無鎖集合ConcurrentBag
代理類的優(yōu)化(比如:,用invokestatic代替invokevirtual)
正如官網(wǎng)的這個對比圖顯示的一樣:它更快
其實話又說回來,要是我一開始就是用第三方數(shù)據(jù)庫,豈不是就不存在這些自己搞出來的幺蛾子了!
比如阿里巴巴的Druid連接池不就是個優(yōu)秀的產(chǎn)品么!它到底有多優(yōu)秀呢?你先看它的使用:
三、其它連接池(如:Druid)3.1、SpringBoot1.0中引用Druid
和前文的SpringBoot1.0中引用HikariCP一樣,先排除默認數(shù)據(jù)源tomcat-jdbc再引用想要使用的連接池
3.1.1、首先引入默認配置的數(shù)據(jù)源處排除掉tomcat-jdbc
- <!--配置默認數(shù)據(jù)源 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- <exclusions>
- <!-- 排除默認的tomcat-jdbc數(shù)據(jù)源 -->
- <exclusion>
- <groupId>org.apache</groupId>
- <artifactId>tomcat-jdbc</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- 引用阿里巴巴的druid數(shù)據(jù)源 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.10</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.0.31</version>
- </dependency>
3.1.2、再在.yml文件中配置Druid數(shù)據(jù)源的相關(guān)信息
- spring:
- # 數(shù)據(jù)源的配置
- datasource:
- # 連接池的配置
- type: com.alibaba.druid.pool.DruidDataSource
- druid:
- initial-size: 5
- max-active: 10
- min-idle: 5
- max-wait: 30000
- pool-prepared-statements: true
- max-pool-prepared-statement-per-connection-size: 20
- validation-query: SELECT 1 FROM DUAL
- validation-query-timeout: 60000
- test-on-borrow: false
- test-on-return: false
- test-while-idle: true
- time-between-eviction-runs-millis: 60000
- min-evictable-idle-time-millis: 100000
3.1.3、再寫個配置類加載數(shù)據(jù)源
- @Configuration
- @ConditionalOnClass(DruidDataSource.class)
- @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = true)
- public class DataSourceConfig {
- @Bean
- @ConfigurationProperties("spring.datasource.druid")
- public DataSource dataSourceOne() {
- return DruidDataSourceBuilder.create().build();
- }
- }
3.1.4、啟動效果:
- 2020-01-17 16:59:32.804 INFO 8520 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
- 2020-01-17 16:59:32.806 INFO 8520 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSourceOne' has been autodetected for JMX exposure
- 2020-01-17 16:59:32.808 INFO 8520 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'statFilter' has been autodetected for JMX exposure
- 2020-01-17 16:59:32.818 INFO 8520 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSourceOne': registering with JMX server as MBean [com.alibaba.druid.spring.boot.autoconfigure:name=dataSourceOne,type=DruidDataSourceWrapper]
- 2020-01-17 16:59:32.822 INFO 8520 --- [ main ] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'statFilter': registering with JMX server as MBean [com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter]
- 2020-01-17 16:59:32.932 INFO 8520 --- [ main ] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 18001 (http)
- 2020-01-17 16:59:32.943 INFO 8520 --- [ main ] c.j.mmzsblog.DatasourceTestApplication :
3.2、SpringBoot2.0中引用Druid
在SpringBoot2.0中引用Druid和在SpringBoot1.0中引入類似;
3.2.1、不需要排除默認配置的數(shù)據(jù)源,直接引入置Druid數(shù)據(jù)源
- <!-- 引用阿里巴巴的druid數(shù)據(jù)源 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.10</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.0.31</version>
- </dependency>
3.2.2、在.yml文件中配置的Druid數(shù)據(jù)源的相關(guān)信息同3.1.3一樣
3.2.3、再寫個配置類加載數(shù)據(jù)源同3.1.3一樣
3.2.4、啟動后你同樣能看到打印出類似的信息
- Located MBean 'dataSourceOne': registering with JMX server as MBean [com.alibaba.druid.spring.boot.autoconfigure:name=dataSourceOne,type=DruidDataSourceWrapper]
3.3、優(yōu)秀在哪?
看了上面的使用,超級簡單又木有?
首先我們看看druid官網(wǎng)給出的幾個傳統(tǒng)連接池之間的對比吧:
從上表可以看出,Druid連接池在性能、監(jiān)控、診斷、安全、擴展性這些方面遠遠超出競品。
官網(wǎng)是這樣介紹它的:
❝Druid連接池是阿里巴巴開源的數(shù)據(jù)庫連接池項目。Druid連接池為監(jiān)控而生,內(nèi)置強大的監(jiān)控功能,監(jiān)控特性不影響性能。功能強大,能防SQL注入,內(nèi)置Loging能診斷Hack應(yīng)用行為。
❞
所以,阿粉我倒騰了這么久,想明白了一件事,我以后還是用阿里爸爸的Druid連接池吧,接入簡單,還自帶監(jiān)控,并且它可是經(jīng)過阿里巴巴各大系統(tǒng)考驗過的產(chǎn)品,值得信賴,省事省心啊。