Spring Boot:集成Druid數據源

綜合概述

數據庫鏈接池負責分配、管理和釋放數據庫鏈接,它容許應用程序重複使用一個現有的數據庫鏈接,而不是再從新創建一個;釋放空閒時間超過最大空閒時間的數據庫鏈接來避免由於沒有釋放數據庫鏈接而引發的數據庫鏈接遺漏。經過數據庫鏈接池能明顯提升對數據庫操做的性能。在Java應用程序開發中,經常使用的鏈接池有DBCP、C3P0、Proxool等。css

Spring Boot默認提供了若干種可用的鏈接池,默認的數據源是:org.apache.tomcat.jdbc.pool.DataSource。而Druid是阿里系提供的一個開源鏈接池,除在鏈接池以外,Druid還提供了很是優秀的數據庫監控和擴展功能。接下來,咱們就來說解如何實現Spring Boot與Druid鏈接池的集成。html

Druid介紹

Druid是阿里開源的一個JDBC應用組件, 其包括三部分:java

  • DruidDriver: 代理Driver,可以提供基於Filter-Chain模式的插件體系。
  • DruidDataSource: 高效可管理的數據庫鏈接池。
  • SQLParser: 實用的SQL語法分析

經過Druid鏈接池中間件, 咱們能夠實現:mysql

  • 能夠監控數據庫訪問性能,Druid內置提供了一個功能強大的StatFilter插件,可以詳細統計SQL的執行性能,這對於線上分析數據庫訪問性能有幫助。
  • 替換傳統的DBCP和C3P0鏈接池中間件。Druid提供了一個高效、功能強大、可擴展性好的數據庫鏈接池。
  • 數據庫密碼加密。直接把數據庫密碼寫在配置文件中,容易致使安全問題。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL執行日誌,Druid提供了不一樣的LogFilter,可以支持Common-Logging、Log4j和JdkLog,你能夠按須要選擇相應的LogFilter,監控你應用的數據庫訪問狀況。
  • 擴展JDBC,若是你要對JDBC層有編程的需求,能夠經過Druid提供的Filter-Chain機制,很方便編寫JDBC層的擴展插件。

更多詳細信息參考官方文檔:https://github.com/alibaba/druid/wikigit

實現案例

接下來,咱們就經過實際案例來說解如何集成Druid數據源,爲了不重複篇幅,此篇教程的源碼基於《Spring Boot:整合MyBatis框架》一篇的源碼實現,讀者請先參考並根據教程連接先行獲取基礎源碼和數據庫內容。github

 

添加相關依賴

打開pom文件,添加 druid 相關的 maven 依賴。web

pom.xmlspring

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

Druid Spring Boot Starter 是阿里官方提供的 Spring Boot 插件,用於幫助在Spring Boot項目中輕鬆集成Druid數據庫鏈接池和監控。sql

更多資料參考:數據庫

Druid: https://github.com/alibaba/druid

Druid Spring Starter: https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

添加相關配置

把原有的數據源配置替換成 druid 數據源並配置數據源相關參數。

application.yml

# Tomcat
server:
  tomcat:
    uri-encoding: UTF-8
    max-threads: 1000
    min-spare-threads: 30
  port: 8080
    #context-path: /springboot

# DataSource
spring:
  datasource:
    name: druidDataSource
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
      username: root
      password: 123456
      filters: stat,wall,log4j,config
      max-active: 100
      initial-size: 1
      max-wait: 60000
      min-idle: 1
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: select 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 50
      max-pool-prepared-statement-per-connection-size: 20

參數說明:

- spring.datasource.druid.max-active  最大鏈接數 
- spring.datasource.druid.initial-size  初始化大小 
- spring.datasource.druid.min-idle  最小鏈接數 
- spring.datasource.druid.max-wait  獲取鏈接等待超時時間 
- spring.datasource.druid.time-between-eviction-runs-millis  間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位是毫秒 
- spring.datasource.druid.min-evictable-idle-time-millis  一個鏈接在池中最小生存的時間,單位是毫秒 
- spring.datasource.druid.filters=config,stat,wall,log4j  配置監控統計攔截的filters,去掉後監控界面SQL沒法進行統計,’wall’用於防火牆

Druid提供如下幾種Filter信息:

自定義配置屬性

若是須要經過定製的配置文件對druid進行自定義屬性配置,在config包中添加屬性配置類。

DruidDataSourceProperties.java

package com.louis.springboot.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DruidDataSourceProperties {

    // jdbc
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    // jdbc connection pool
    private int initialSize;
    private int minIdle;
    private int maxActive = 100;
    private long maxWait;
    private long timeBetweenEvictionRunsMillis;
    private long minEvictableIdleTimeMillis;
    private String validationQuery;
    private boolean testWhileIdle;
    private boolean testOnBorrow;
    private boolean testOnReturn;
    private boolean poolPreparedStatements;
    private int maxPoolPreparedStatementPerConnectionSize;
    // filter
    private String filters;

    public int getInitialSize() {
        return initialSize;
    }

    public void setInitialSize(int initialSize) {
        this.initialSize = initialSize;
    }

    public int getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public int getMaxActive() {
        return maxActive;
    }

    public void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public long getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(long maxWait) {
        this.maxWait = maxWait;
    }

    public long getTimeBetweenEvictionRunsMillis() {
        return timeBetweenEvictionRunsMillis;
    }

    public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    public long getMinEvictableIdleTimeMillis() {
        return minEvictableIdleTimeMillis;
    }

    public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    public String getValidationQuery() {
        return validationQuery;
    }

    public void setValidationQuery(String validationQuery) {
        this.validationQuery = validationQuery;
    }

    public boolean isTestWhileIdle() {
        return testWhileIdle;
    }

    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }

    public boolean isTestOnBorrow() {
        return testOnBorrow;
    }

    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    public boolean isTestOnReturn() {
        return testOnReturn;
    }

    public void setTestOnReturn(boolean testOnReturn) {
        this.testOnReturn = testOnReturn;
    }

    public boolean isPoolPreparedStatements() {
        return poolPreparedStatements;
    }

    public void setPoolPreparedStatements(boolean poolPreparedStatements) {
        this.poolPreparedStatements = poolPreparedStatements;
    }

    public int getMaxPoolPreparedStatementPerConnectionSize() {
        return maxPoolPreparedStatementPerConnectionSize;
    }

    public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
    }

    public String getFilters() {
        return filters;
    }

    public void setFilters(String filters) {
        this.filters = filters;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

Druid Spring Starter 簡化了不少配置,若是默認配置知足不了你的需求,能夠自定義配置。更多配置參考:

Druid Spring Starter: https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

配置Servlet和Filter

在config包中添加一個DruidConfig配置類。

DruidConfig.java

package com.louis.springboot.demo.config;
import java.sql.SQLException;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;

@Configuration
@EnableConfigurationProperties({DruidDataSourceProperties.class})
public class DruidConfig {
    @Autowired
    private DruidDataSourceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    public DataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(properties.getDriverClassName());
        druidDataSource.setUrl(properties.getUrl());
        druidDataSource.setUsername(properties.getUsername());
        druidDataSource.setPassword(properties.getPassword());
        druidDataSource.setInitialSize(properties.getInitialSize());
        druidDataSource.setMinIdle(properties.getMinIdle());
        druidDataSource.setMaxActive(properties.getMaxActive());
        druidDataSource.setMaxWait(properties.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(properties.getValidationQuery());
        druidDataSource.setTestWhileIdle(properties.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
        druidDataSource.setTestOnReturn(properties.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize());

        try {
            druidDataSource.setFilters(properties.getFilters());
            druidDataSource.init();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return druidDataSource;
    }

    /**
     * 註冊Servlet信息, 配置監控視圖
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean<Servlet> druidServlet() {
        ServletRegistrationBean<Servlet> servletRegistrationBean = new ServletRegistrationBean<Servlet>(new StatViewServlet(), "/druid/*");

        //白名單:
        servletRegistrationBean.addInitParameter("allow","192.168.1.195");
        //IP黑名單 (存在共同時,deny優先於allow) : 若是知足deny的話提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.addInitParameter("deny","192.168.1.119");
        //登陸查看信息的帳號密碼, 用於登陸Druid監控後臺
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        //是否可以重置數據.
        servletRegistrationBean.addInitParameter("resetEnable", "true");
        return servletRegistrationBean;

    }

    /**
     * 註冊Filter信息, 監控攔截器
     *
     * @return
     */
    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean<Filter> filterRegistrationBean() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

說明:

- @EnableConfigurationProperties({DruidDataSourceProperties.class})  用於導入上一步Druid的配置信息 
- public ServletRegistrationBean druidServlet()  至關於Web Servlet配置 
- public FilterRegistrationBean filterRegistrationBean()  至關於Web Filter配置

若是不使用上述的Servlet和Filter配置, 也能夠經過下述監控器配置實現:

配置監控攔截器(至關於FilterRegistrationBean)

DruidStatFilter.java

package com.louis.kitty.boot.config;

import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import com.alibaba.druid.support.http.WebStatFilter;

/**   
 * 配置監控攔截器, druid監控攔截器   
 */    
@WebFilter(filterName="druidWebStatFilter",    
urlPatterns="/*",    
initParams={    
    @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"), // 忽略資源    
})   
public class DruidStatFilter extends WebStatFilter {  

} 

配置Druid監控視圖(至關於ServletRegistrationBean)

DruidStatViewServlet.java

package com.louis.kitty.boot.config;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import com.alibaba.druid.support.http.StatViewServlet;

/**   
 * druid監控視圖配置   
 */    
@WebServlet(urlPatterns = "/druid/*", initParams={    
    @WebInitParam(name="allow",value="192.168.6.195"),    // IP白名單 (沒有配置或者爲空,則容許全部訪問)    
    @WebInitParam(name="deny",value="192.168.6.73"),    // IP黑名單 (存在共同時,deny優先於allow)    
    @WebInitParam(name="loginUsername",value="admin"),    // 用戶名    
    @WebInitParam(name="loginPassword",value="admin"),    // 密碼    
    @WebInitParam(name="resetEnable",value="true")    // 禁用HTML頁面上的「Reset All」功能    
})   
public class DruidStatViewServlet extends StatViewServlet {  
    private static final long serialVersionUID = 7359758657306626394L;  
}  

應用啓動問題

到這裏Druid的配置就完成了,可是此時啓動應用,發現出錯了,錯誤內容大體以下,提示 log4j 相關的類查找不到,而後查看依賴,發現確實沒有 log4j 的依賴,有些奇怪,嘗試了一下,也沒發現其餘辦法,手動加一下吧。

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'druidDataSource' defined in class path resource [com/louis/kitty/boot/config/DruidConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'druidDataSource' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/log4j/Priority
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:398) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:330) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1258) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at com.louis.kitty.boot.KittyApplication.main(KittyApplication.java:10) [classes/:na]

    ...

Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_131]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_131]
... 49 common frames omitted

添加 log4j 依賴

pom.xml 添加 log4j 依賴,最新版本是 1.2.17。

<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

添加 log4j 配置

在 resources 目錄下,新建一個 log4j.properties 參數配置文件,並鍵入以下內容:

### set log levels ###    
log4j.rootLogger = INFO,DEBUG, console, infoFile, errorFile ,debugfile,mail 
LocationInfo=true    

log4j.appender.console = org.apache.log4j.ConsoleAppender  
log4j.appender.console.Target = System.out  
log4j.appender.console.layout = org.apache.log4j.PatternLayout 

log4j.appender.console.layout.ConversionPattern =[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%p]:%m   %x %n 

log4j.appender.infoFile = org.apache.log4j.DailyRollingFileAppender  
log4j.appender.infoFile.Threshold = INFO  
log4j.appender.infoFile.File = D:/logs/log
log4j.appender.infoFile.DatePattern = '.'yyyy-MM-dd'.log'  
log4j.appender.infoFile.Append=true
log4j.appender.infoFile.layout = org.apache.log4j.PatternLayout  
log4j.appender.infoFile.layout.ConversionPattern =[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%p]:%m  %x %n 

log4j.appender.errorFile = org.apache.log4j.DailyRollingFileAppender  
log4j.appender.errorFile.Threshold = ERROR  
log4j.appender.errorFile.File = D:/logs/error  
log4j.appender.errorFile.DatePattern = '.'yyyy-MM-dd'.log'  
log4j.appender.errorFile.Append=true  
log4j.appender.errorFile.layout = org.apache.log4j.PatternLayout  
log4j.appender.errorFile.layout.ConversionPattern =[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%p]:%m  %x %n

#log4j.appender.debugfile = org.apache.log4j.DailyRollingFileAppender  
#log4j.appender.debugfile.Threshold = DEBUG  
#log4j.appender.debugfile.File = D:/logs/debug  
#log4j.appender.debugfile.DatePattern = '.'yyyy-MM-dd'.log'  
#log4j.appender.debugfile.Append=true  
#log4j.appender.debugfile.layout = org.apache.log4j.PatternLayout  
#log4j.appender.debugfile.layout.ConversionPattern =[%d{yyyy-MM-dd HH:mm:ss,SSS}]-[%p]:%m  %x %n

配置完成後,從新編譯啓動,發現已經能夠啓動了。按理說,Spring Boot 已經集成了 log4j, 這個問題出現的有點奇怪,有知道答案的朋友,歡迎賜教,感激涕零。

查看監控視圖

登陸界面

啓動應用,訪問: http://localhost:8080/druid/login.html, 進入Druid監控後臺頁面。

注意:登陸用戶名和密碼,就是在DruidConfig配置類中配置的,查看並進行登陸。

登陸首頁

首頁信息。

數據源

顯示鏈接數據源的相關信息。

SQL監控

分別訪問下面兩個接口以後,SQL監控的記錄結果。

http://localhost:8080/user/findByUserId?userId=1

http://localhost:8080/user/findAll

URI監控

分別訪問下面兩個接口以後,URI監控的記錄結果。

http://localhost:8080/user/findByUserId?userId=1

http://localhost:8080/user/findAll

 

胡言亂語

要想數據庫性能好,數據庫調優少不了。

服務器配置須要弄,SQL調優也得搞。

要問數據源哪家好,阿里DRUID準沒跑。

SQL監控作得好,語句調優沒煩惱。

參考資料

官方網站:https://druid.apache.org/

官方文檔:https://github.com/alibaba/druid/wiki

在線文檔:http://tool.oschina.net/apidocs/apidoc?api=druid0.26

相關導航

Spring Boot 系列教程目錄導航

Spring Boot:快速入門教程

Spring Boot:整合Swagger文檔

Spring Boot:整合MyBatis框架

Spring Boot:實現MyBatis分頁

源碼下載

碼雲:https://gitee.com/liuge1988/spring-boot-demo.git


做者:朝雨憶輕塵
出處:https://www.cnblogs.com/xifengxiaoma/ 
版權全部,歡迎轉載,轉載請註明原文做者及出處。

相關文章
相關標籤/搜索