最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot + Druid + Dynamic Datasource 多數(shù)據(jù)源配置方案

 更新時間:2025年08月12日 10:03:25   作者:菠蘿蚊鴨  
本文通過實(shí)例代碼給大家介紹SpringBoot整合Druid與多數(shù)據(jù)源配置,涵蓋自動裝配流程、數(shù)據(jù)源動態(tài)切換方案及監(jiān)控功能實(shí)現(xiàn),感興趣的朋友一起看看吧

1、依賴

<dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
     <version>4.3.1</version>
     <exclusions>
         <exclusion>
             <groupId>com.alibaba</groupId>
             <artifactId>druid-spring-boot-starter</artifactId>
         </exclusion>
     </exclusions>
 </dependency>
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid-spring-boot-starter</artifactId>
     <version>1.2.24<</version>
 </dependency>

2、application.yml

特別注意:多數(shù)據(jù)源 druid 要配置到每一個數(shù)據(jù)源里面

spring:
  application:
    name: DynamicDatasource
  datasource:
    druid:
      stat-view-servlet:
        enabled: true
        allow:
        deny:
        reset-enable: false
        login-username: admin
        login-password: 123456
        url-pattern: /druid/*
      web-stat-filter:
        enabled: true
        #對這些請求放行
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
        #攔截該項(xiàng)目下的一切請求
        url-pattern: /*
        session-stat-enable: true
        principal-session-name: session_name
        principal-cookie-name: cookie_name
        profile-enable: true
      # 包匹配,表示匹配以com.github.wxhnyfy.dynamicdatasource開頭的包名,多個用逗號隔開
      aop-patterns: com.github.wxhnyfy.dynamicdatasource.*
    dynamic:
      primary: master # 設(shè)置默認(rèn)的數(shù)據(jù)源或者數(shù)據(jù)源組,默認(rèn)值即為 master
      datasource:
        master:
          #設(shè)置默認(rèn)的數(shù)據(jù)源
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/region?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
          username: root
          password: 123456
          type: com.alibaba.druid.pool.DruidDataSource
          # druid連接池設(shè)置
          druid:
            # 配置初始化線程數(shù)
            initialSize: 5
            # 最小線程數(shù)
            minIdle: 5
            # CPU核數(shù)+1,也可以大些但不要超過20,數(shù)據(jù)庫加鎖時連接過多性能下降
            maxActive: 11
            # 最大等待時間,內(nèi)網(wǎng):800,外網(wǎng):1200(三次握手1s)
            maxWait: 60000
            # 連接可空閑存活時間(ms)
            timeBetweenEvictionRunsMillis: 60000
            # 連接保持空閑而不被驅(qū)逐的最長存活時間(ms)
            minEvictableIdleTimeMillis: 300000
            # 用來檢測連接是否有效的sql,如果validationQuery為空,那么testOnBorrow、testOnReturn、testWhileIdle這三個參數(shù)都不會起作用
            validationQuery: SELECT 1
            # 建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效;
            testWhileIdle: true
            # 建議配置為false,申請連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能。
            testOnBorrow: false
            # 建議配置為false,歸還連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能;
            testOnReturn: false
            # PSCache對支持游標(biāo)的數(shù)據(jù)庫性能提升巨大,oracle建議開啟,mysql下建議關(guān)閉
            poolPreparedStatements: false
            # 保持minIdle數(shù)量的長連接
            keepAlive: true
            # 要啟用PSCache,必須配置大于0,當(dāng)大于0時,poolPreparedStatements自動觸發(fā)修改為true。
            # 在Druid中,不會存在Oracle下PSCache占用內(nèi)存過多的問題,可以把這個數(shù)值配置大一些,比如說100。缺省值為-1
            # 開啟poolPreparedStatments后生效
            maxPoolPreparedStatementPerConnectionSize: 20
            # 是否合并多個DruidDataSource的監(jiān)控數(shù)據(jù)
            useGlobalDataSourceStat: true
            # 配置監(jiān)控統(tǒng)計攔截的filters
            filters: stat,wall,slf4j
            stat:
              logSlowSql: true
              slowSqlMillis: 2000
              mergeSql: true
              dbType: mysql
            wall:
              # 可配置項(xiàng)參考類:com.alibaba.druid.wall.WallConfig
              multi-statement-allow: true
              alter-table-allow: false
              drop-table-allow: false
            slf4j:
              # 只有當(dāng) isStatementExecutableSqlLogEnable() isStatementLogEnabled() 都為ture的情況才打印 可執(zhí)行sql
              # 在{# LogFilter#logExecutableSql }使用
              statement-executable-sql-log-enable: true
              # 在{# LogFilter#logExecutableSql }使用
              statement-log-enabled: true
              statement-create-after-log-enabled: false
              statement-log-error-enabled: true
              result-set-log-enabled: false
              #statementPrepareAfterLogEnable
              # 準(zhǔn)備好的sql語句打?。ù藭r為執(zhí)行前)未進(jìn)行參數(shù)拼接
              statement-prepare-after-log-enabled: false
              #isStatementParameterSetLogEnabled
              #打印參數(shù)
              statement-parameter-set-log-enabled: false
              #statementExecuteAfterLogEnable
              #sql語句執(zhí)行完成后打?。▓?zhí)行后)未進(jìn)行參數(shù)拼接
              statement-execute-after-log-enabled: false
              #statementCloseAfterLogEnable
              statement-close-after-log-enabled: false
              #不打印清除參數(shù)日志
              statement-parameter-clear-log-enable: false
            # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
            connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=2000
        slave:
          url: jdbc:mysql://localhost:3307/region?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          # druid連接池設(shè)置
          druid:
            # 配置初始化線程數(shù)
            initialSize: 5
            # 最小線程數(shù)
            minIdle: 5
            # CPU核數(shù)+1,也可以大些但不要超過20,數(shù)據(jù)庫加鎖時連接過多性能下降
            maxActive: 11
            # 最大等待時間,內(nèi)網(wǎng):800,外網(wǎng):1200(三次握手1s)
            maxWait: 60000
            # 連接可空閑存活時間(ms)
            timeBetweenEvictionRunsMillis: 60000
            # 連接保持空閑而不被驅(qū)逐的最長存活時間(ms)
            minEvictableIdleTimeMillis: 300000
            # 用來檢測連接是否有效的sql,如果validationQuery為空,那么testOnBorrow、testOnReturn、testWhileIdle這三個參數(shù)都不會起作用
            validationQuery: SELECT 1
            # 建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效;
            testWhileIdle: true
            # 建議配置為false,申請連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能。
            testOnBorrow: false
            # 建議配置為false,歸還連接時執(zhí)行validationQuery檢測連接是否有效,做了這個配置會降低性能;
            testOnReturn: false
            # PSCache對支持游標(biāo)的數(shù)據(jù)庫性能提升巨大,oracle建議開啟,mysql下建議關(guān)閉
            poolPreparedStatements: false
            # 保持minIdle數(shù)量的長連接
            keepAlive: true
            # 要啟用PSCache,必須配置大于0,當(dāng)大于0時,poolPreparedStatements自動觸發(fā)修改為true。
            # 在Druid中,不會存在Oracle下PSCache占用內(nèi)存過多的問題,可以把這個數(shù)值配置大一些,比如說100。缺省值為-1
            # 開啟poolPreparedStatments后生效
            maxPoolPreparedStatementPerConnectionSize: 20
            # 是否合并多個DruidDataSource的監(jiān)控數(shù)據(jù)
            useGlobalDataSourceStat: true
            # 配置監(jiān)控統(tǒng)計攔截的filters
            filters: stat,wall,slf4j
            stat:
              logSlowSql: true
              slowSqlMillis: 2000
              mergeSql: true
              dbType: mysql
            wall:
              # 可配置項(xiàng)參考類:com.alibaba.druid.wall.WallConfig
              multi-statement-allow: true
              alter-table-allow: false
              drop-table-allow: false
            slf4j:
              # 只有當(dāng) isStatementExecutableSqlLogEnable() isStatementLogEnabled() 都為ture的情況才打印 可執(zhí)行sql
              # 在{# LogFilter#logExecutableSql }使用
              statement-executable-sql-log-enable: true
              # 在{# LogFilter#logExecutableSql }使用
              statement-log-enabled: true
              statement-create-after-log-enabled: false
              statement-log-error-enabled: true
              result-set-log-enabled: false
              #statementPrepareAfterLogEnable
              # 準(zhǔn)備好的sql語句打?。ù藭r為執(zhí)行前)未進(jìn)行參數(shù)拼接
              statement-prepare-after-log-enabled: false
              #isStatementParameterSetLogEnabled
              #打印參數(shù)
              statement-parameter-set-log-enabled: false
              #statementExecuteAfterLogEnable
              #sql語句執(zhí)行完成后打印(執(zhí)行后)未進(jìn)行參數(shù)拼接
              statement-execute-after-log-enabled: false
              #statementCloseAfterLogEnable
              statement-close-after-log-enabled: false
              #不打印清除參數(shù)日志
              statement-parameter-clear-log-enable: false
            # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
            connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=2000

3、多數(shù)據(jù)源 Duid 自動裝配詳解

3.1、自動裝配 spring.datasource.dynamic

由于我們引入了 dynamic-datasource-spring-boot-starter,啟動時會優(yōu)先自動裝配 com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration,并且在類 com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure 之前裝配

會自動裝配以下屬性,參考類 com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties,datasource 就是我們配置的多數(shù)據(jù)源

3.2、自動裝配多數(shù)據(jù)源 datasource

參考類 com.baomidou.dynamic.datasource.creator.DataSourceProperty

3.3、自動裝配每個數(shù)據(jù)源下的 duid 配置

這個配置和 Druid 的層級稍有一些不同
參考類 com.baomidou.dynamic.datasource.creator.druid.DruidConfig

數(shù)據(jù)源的 Filter 配置

3.4、自動裝配 StatViewServlet

參考類:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidStatViewServletConfiguration

3.5、自動裝配 WebStatFilter

參考類:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidWebStatFilterConfiguration

3.6、自動裝配 AopPatterns

參考類:com.alibaba.druid.spring.boot.autoconfigure.stat.DruidSpringAopConfiguration

3.7、Filter 配置類

  • wall: com.alibaba.druid.wall.WallConfig
  • slf4j、log4j、log4j2、commonsLog: 四個日志 filter 只有實(shí)現(xiàn)不同,配置類都是同一個,com.alibaba.druid.filter.logging.LogFilter
  • stat:com.alibaba.druid.filter.stat.StatFilter

日志 Filter 要引入對應(yīng)的依賴,Druid 的 LoggerName 在類 com.alibaba.druid.filter.logging LogFilter,配置日志打印級別時需要使用下面的 LoggerName

4、Druid 監(jiān)控頁面

4.1、首頁

訪問地址:http://IP:端口/上下文/druid/index.html

4.2、數(shù)據(jù)源列表

要看每一個數(shù)據(jù)源的 filter 類名,看一下是否和啟用的 Filter 一致,再看一起其他的配置是否能正常讀取

4.2、SQL 監(jiān)控

執(zhí)行過 SQL 后,Druid 能對 SQL 進(jìn)行監(jiān)控,但是不能區(qū)分是哪個數(shù)據(jù)源執(zhí)行的。由于我們開啟了SQL合并,所以看到的SQL都會帶有占位符

點(diǎn)擊去能看到每條SQL的執(zhí)行詳情。

4.3、SQL 防火墻

能對黑白名單進(jìn)行統(tǒng)計,但是不能區(qū)分是哪個數(shù)據(jù)源執(zhí)行的

示例,我們在 spring.datasource.dynamic.datasource.master.wall 配置了不能執(zhí)行 select 語句

SQL 會執(zhí)行報錯

能正常監(jiān)控到黑名單 SQL

4.4、Web 應(yīng)用

4.5、URI 監(jiān)控

能監(jiān)控到執(zhí)行SQL的請求

4.6、Web Session 監(jiān)控

4.7、Spring 監(jiān)控

根據(jù) aop-pattern 配置包名進(jìn)行監(jiān)控

4.8、JSON API

把各個頁面的信息轉(zhuǎn)為 JSON 數(shù)據(jù)

5、動態(tài)切換數(shù)據(jù)源

這里給出一個參考解決方案

5.1、數(shù)據(jù)源枚舉

public enum DataSourceEnum {
    MASTER("master"),
    SLAVE("slave");
    private String value;
    DataSourceEnum(String value) {
        this.value = value;
    }
    public String getValue() {
        return value;
    }
}

5.2、Controller 層

在 Controller 的每個方法入?yún)⒍技由蠑?shù)據(jù)源枚舉

@ApiOperation(value = "執(zhí)行自定義SQL")
@ApiImplicitParams({
        @ApiImplicitParam(name = "envCode", value = "數(shù)據(jù)源標(biāo)識", required = true, paramType = "query", example = "MASTER", dataTypeClass = DataSourceEnum.class),
        @ApiImplicitParam(name = "query", value = "查詢字符串", required = true, paramType = "query", example = "select * from chinapostoffice limit 100", dataTypeClass = String.class),
})
@GetMapping("/getChinaPostOffice ")
public Response<JSONArray> getChinaPostOffice(@RequestParam DataSourceEnum envCode,
                                              @RequestParam String query
) {
    logger.info(">>> query: {}", query);
    List<Map<String, Object>> list = customMapper.selectList(query);
    logger.info(">>> 總共 {} 條數(shù)據(jù)", list.size());
    logger.info(">>> 數(shù)據(jù): {}", JSONArray.from(list, JSONWriter.Feature.WriteMapNullValue).toJSONString(JSONWriter.Feature.WriteMapNullValue));
    return new Response<JSONArray>().success(JSONArray.from(list, JSONWriter.Feature.WriteMapNullValue));
}

5.3、AOP 根據(jù)入?yún)⒆詣忧袚Q數(shù)據(jù)源

DynamicDataSourceContextHolder 實(shí)現(xiàn)原理,可參考源碼,解析得很詳細(xì)了

@Aspect
@Component
// 確保在事務(wù)切面之前執(zhí)行
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AutoSwitchDataSourceAop {
    private static final Logger logger = LoggerFactory.getLogger(AutoSwitchDataSourceAop.class);
    /**
     * 當(dāng)前指定的默認(rèn)數(shù)據(jù)源
     */
    @Value("${spring.datasource.dynamic.primary}")
    private String dynamicPrimaryDataSource;
    /**
     * 定義匹配需要切換數(shù)據(jù)源的方法的切點(diǎn)
     * 匹配com.github.wxhnyfy.dynamicdatasource.controller包、com.github.wxhnyfy.dynamicdatasource.impl.service包下所有包含DataSourceEnum參數(shù)的方法
     * 支持DataSourceEnum參數(shù)在任意參數(shù)位置(不限于第一個參數(shù))
     *
     * @param joinPoint 切點(diǎn)
     * @return 目標(biāo)執(zhí)行方法
     * @throws Throwable 異常
     */
    @Around("execution(* com.github.wxhnyfy.dynamicdatasource.controller.*.*(com.github.wxhnyfy.dynamicdatasource.enums.DataSourceEnum, ..)) " +
         "|| execution(* com.github.wxhnyfy.dynamicdatasource.impl.service.*.*(com.github.wxhnyfy.dynamicdatasource.enums.DataSourceEnum, ..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        logger.info("進(jìn)入 SwitchDataSourceAspect 的方法名: {}", methodName);
        logger.debug("當(dāng)前指定的默認(rèn)數(shù)據(jù)源:{}", dynamicPrimaryDataSource);
        DataSourceEnum envCode = null;
        try {
            // 獲取方法參數(shù)中的EnvCode值
            envCode = extractEnvCode(joinPoint);
            // 切換數(shù)據(jù)源
            if (envCode != null) {
                logger.info("數(shù)據(jù)庫環(huán)境標(biāo)識:{}", envCode);
                String previousDs = DynamicDataSourceContextHolder.peek();
                logger.info("方法 [{}] 切換數(shù)據(jù)源: {} -> {}", methodName, previousDs, envCode.getValue());
                DynamicDataSourceContextHolder.push(envCode.getValue());
            }
            // 執(zhí)行目標(biāo)方法
            return joinPoint.proceed();
        } finally {
            // 清理數(shù)據(jù)源(恢復(fù)到默認(rèn)數(shù)據(jù)源)
            if (envCode != null) {
                DynamicDataSourceContextHolder.clear();
            }
        }
    }
    /**
     * 通過反射獲取方法參數(shù)
     * 自動識別DataSourceEnum類型的參數(shù)
     * 支持任意位置的DataSourceEnum參數(shù)
     *
     * @param joinPoint 切點(diǎn)
     * @return DataSourceEnum參數(shù)
     */
    private DataSourceEnum extractEnvCode(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Parameter[] parameters = signature.getMethod().getParameters();
        // 遍歷參數(shù)查找EnvCode類型的參數(shù)
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].getType().isAssignableFrom(DataSourceEnum.class)) {
                Object arg = joinPoint.getArgs()[i];
                if (arg instanceof DataSourceEnum) {
                    return (DataSourceEnum) arg;
                }
            }
        }
        return null;
    }
}

6、日志輸出效果

Mybatis-Plus 我們使用 org.apache.ibatis.logging.slf4j.Slf4jImpl 日志實(shí)現(xiàn),配置對應(yīng)的日志級別

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
logging:
  level:
    root: info
    # 注意,logback不支持**匹配
    com.github.wxhnyfy.**.mapper: debug
    druid.sql.Statement: debug

日志輸出效果如下圖

到此這篇關(guān)于SpringBoot + Druid + Dynamic Datasource 多數(shù)據(jù)源配置的文章就介紹到這了,更多相關(guān)SpringBoot Druid Dynamic Datasource 多數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中內(nèi)存分配的幾種方法

    Java中內(nèi)存分配的幾種方法

    本文主要介紹Java中幾種分配內(nèi)存的方法。我們會看到如何使用sun.misc.Unsafe來統(tǒng)一操作任意類型的內(nèi)存。以前用C語言開發(fā)的同學(xué)通常都希望能在Java中通過較底層的接口來操作內(nèi)存,他們一定會對本文中要講的內(nèi)容感興趣
    2014-03-03
  • Java8的Lambda和排序

    Java8的Lambda和排序

    這篇文章主要介紹了Java8的Lambda和排序,對數(shù)組和集合進(jìn)行排序是Java 8 lambda令人驚奇的一個應(yīng)用,我們可以實(shí)現(xiàn)一個Comparators來實(shí)現(xiàn)各種排序,下面文章將有案例詳細(xì)說明,想要了解得小伙伴可以參考一下
    2021-11-11
  • java servlet獲得客戶端相關(guān)信息的簡單代碼

    java servlet獲得客戶端相關(guān)信息的簡單代碼

    這篇文章主要介紹了java servlet獲得客戶端相關(guān)信息的簡單代碼,有需要的朋友可以參考一下
    2013-12-12
  • java中的session對象如何獲取

    java中的session對象如何獲取

    這篇文章主要介紹了java中的session對象如何獲取,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java數(shù)組動態(tài)擴(kuò)容的實(shí)現(xiàn)示例

    Java數(shù)組動態(tài)擴(kuò)容的實(shí)現(xiàn)示例

    本文主要介紹了Java數(shù)組動態(tài)擴(kuò)容的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-12-12
  • Java利用Spire.XLS?for?Java實(shí)現(xiàn)查找并替換Excel中的數(shù)據(jù)

    Java利用Spire.XLS?for?Java實(shí)現(xiàn)查找并替換Excel中的數(shù)據(jù)

    在日常的數(shù)據(jù)處理工作中,Excel?文件無疑是最常見的載體之一,本文將深入探討如何借助?Java?語言和強(qiáng)大的?Spire.XLS?for?Java?自動化處理?Excel?文件的查找替換任務(wù),感興趣的小伙伴可以了解下
    2025-09-09
  • Spring如何自定義加載配置文件(分層次加載)

    Spring如何自定義加載配置文件(分層次加載)

    這篇文章主要介紹了Spring如何自定義加載配置文件(分層次加載)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Redis緩存及熱點(diǎn)key問題解決方案

    Redis緩存及熱點(diǎn)key問題解決方案

    這篇文章主要介紹了Redis緩存及熱點(diǎn)key問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • 最新評論

    青河县| 潢川县| 大宁县| 且末县| 驻马店市| 驻马店市| 南投市| 吉木萨尔县| 九龙坡区| 安仁县| 新密市| 犍为县| 高邑县| 韶山市| 邛崃市| 涟水县| 邻水| 读书| 托克托县| 定陶县| 南阳市| 姜堰市| 丽水市| 夹江县| 泗洪县| 五峰| 赤壁市| 肥西县| 吴旗县| 于田县| 青铜峡市| 博乐市| 扶沟县| 中超| 九寨沟县| 罗平县| 云安县| 邯郸县| 上饶县| 山阳县| 馆陶县|