<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${dynamic.version}</version> </dependency> 簡介 前兩篇博客介紹了用基本的方式做多數據源,可以應對一般的情況,但是遇到一些復雜的情況就需要擴展下功能了,比如:動態增減數據源、數據源分組,純粹多庫 讀寫分離 一主多從、從其他數據庫或者配置中心讀取數據源等等。其實就算沒有這些需求,使用這個實現多數據源也比之前使用AbstractRoutingDataSource要便捷的多 dynamic-datasource-spring-boot-starter 是一個基於springboot的快速集成多數據源的啟動器。 github: https://github.com/baomidou/dynamic-datasource-spring-boot-starter 文檔: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/wiki 它跟mybatis-plus是一個生態圈里的,很容易集成mybatis-plus 特性: 數據源分組,適用於多種場景 純粹多庫 讀寫分離 一主多從 混合模式。 內置敏感參數加密和啟動初始化表結構schema數據庫database。 提供對Druid,Mybatis-Plus,P6sy,Jndi的快速集成。 簡化Druid和HikariCp配置,提供全局參數配置。 提供自定義數據源來源接口(默認使用yml或properties配置)。 提供項目啟動后增減數據源方案。 提供Mybatis環境下的 純讀寫分離 方案。 使用spel動態參數解析數據源,如從session,header或參數中獲取數據源。(多租戶架構神器) 提供多層數據源嵌套切換。(ServiceA >>> ServiceB >>> ServiceC,每個Service都是不同的數據源) 提供 不使用注解 而 使用 正則 或 spel 來切換數據源方案(實驗性功能)。 基於seata的分布式事務支持。 ============================================================================================================== 核心配置類 DynamicDataSourceAutoConfiguration @Bean @ConditionalOnMissingBean public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); // 改造時自定義, 並覆蓋核心方法 dataSource.setPrimary(properties.getPrimary()); dataSource.setStrategy(properties.getStrategy()); dataSource.setProvider(dynamicDataSourceProvider); dataSource.setP6spy(properties.getP6spy()); dataSource.setStrict(properties.getStrict()); return dataSource; } 抽象動態獲取數據源 AbstractRoutingDataSource /** * 子類實現決定最終數據源 * * @return 數據源 */ protected abstract DataSource determineDataSource(); @Override public Connection getConnection() throws SQLException { return determineDataSource().getConnection(); } 核心動態數據源組件 DynamicRoutingDataSource /** * 所有數據庫 */ private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>(); /** * 分組數據庫 */ private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>(); @Override public DataSource determineDataSource() { return getDataSource(DynamicDataSourceContextHolder.peek()); } private DataSource determinePrimaryDataSource() { log.debug("從默認數據源中返回數據"); return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary); } /** * 獲取當前所有的數據源 * * @return 當前所有數據源 */ public Map<String, DataSource> getCurrentDataSources() { return dataSourceMap; } /** * 獲取的當前所有的分組數據源 * * @return 當前所有的分組數據源 */ public Map<String, DynamicGroupDataSource> getCurrentGroupDataSources() { return groupDataSources; } /** * 獲取數據源 * * @param ds 數據源名稱 * @return 數據源 */ public DataSource getDataSource(String ds) { if (StringUtils.isEmpty(ds)) { return determinePrimaryDataSource(); } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) { log.debug("從 {} 組數據源中返回數據源", ds); return groupDataSources.get(ds).determineDataSource(); } else if (dataSourceMap.containsKey(ds)) { log.debug("從 {} 單數據源中返回數據源", ds); return dataSourceMap.get(ds); } if (strict) { throw new RuntimeException("不能找到名稱為" + ds + "的數據源"); } return determinePrimaryDataSource(); } ===================================================================================================
如果有特殊業務, 例如多數據源事務控制(單個節點(分布式事務另當別論)), 可以參考以上核心代碼加以改造, 簡記....................以防忘記!!!!!!!!!