<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();
}
===================================================================================================
如果有特殊業務, 例如多數據源事務控制(單個節點(分布式事務另當別論)), 可以參考以上核心代碼加以改造, 簡記....................以防忘記!!!!!!!!!