dynamic-datasource数据源路由规则:数据库类型
在现代应用开发中,随着数据量的增长和业务复杂度的提升,单一数据源往往难以满足系统需求。dynamic-datasource作为一款优秀的多数据源解决方案,为Spring Boot应用提供了灵活高效的数据源管理能力。本文将深入探讨dynamic-datasource的数据源路由规则,帮助开发者更好地理解和应用这一强大工具。
核心路由组件
dynamic-datasource的数据源路由功能核心由DynamicRoutingDataSource类实现,该类继承自AbstractRoutingDataSource,并实现了InitializingBean和DisposableBean接口,负责数据源的初始化、路由和销毁等关键操作。
public class DynamicRoutingDataSource extends AbstractRoutingDataSource implements InitializingBean, DisposableBean {
// 核心实现代码
}
数据源存储结构
DynamicRoutingDataSource使用两个重要的Map结构来存储数据源信息:
dataSourceMap: 存储所有已配置的数据源,key为数据源名称,value为数据源实例。groupDataSources: 存储分组数据源,key为分组名称,value为GroupDataSource实例。
这两个Map的定义如下:
/**
* 所有数据库
*/
private final Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
/**
* 分组数据库
*/
private final Map<String, GroupDataSource> groupDataSources = new ConcurrentHashMap<>();
路由策略接口
dynamic-datasource定义了DynamicDataSourceStrategy接口,作为所有数据源路由策略的基础。该接口只有一个determineKey方法,用于从数据源列表中选择一个数据源。
public interface DynamicDataSourceStrategy {
/**
* determine a database from the given dataSources
*
* @param dsNames given dataSources
* @return final dataSource
*/
String determineKey(List<String> dsNames);
}
内置路由策略
dynamic-datasource提供了两种内置的路由策略:负载均衡策略和随机策略。
负载均衡策略
LoadBalanceDynamicDataSourceStrategy实现了基于轮询的负载均衡策略。它使用一个原子整数作为计数器,每次请求时自增并取模,从而实现数据源的轮询选择。
public class LoadBalanceDynamicDataSourceStrategy implements DynamicDataSourceStrategy {
/**
* 负载均衡计数器
*/
private final AtomicInteger index = new AtomicInteger(0);
@Override
public String determineKey(List<String> dsNames) {
return dsNames.get(Math.abs(index.getAndAdd(1) % dsNames.size()));
}
}
随机策略
RandomDynamicDataSourceStrategy实现了随机选择数据源的策略。它使用ThreadLocalRandom来生成随机数,从而在数据源列表中随机选择一个数据源。
public class RandomDynamicDataSourceStrategy implements DynamicDataSourceStrategy {
@Override
public String determineKey(List<String> dsNames) {
return dsNames.get(ThreadLocalRandom.current().nextInt(dsNames.size()));
}
}
数据源路由流程
dynamic-datasource的数据源路由流程主要包括以下几个关键步骤:
1. 获取数据源标识
determineDataSource方法是路由的入口点,它通过DynamicDataSourceContextHolder.peek()获取当前线程的数据源标识(dsKey)。
@Override
public DataSource determineDataSource() {
String dsKey = DynamicDataSourceContextHolder.peek();
return getDataSource(dsKey);
}
2. 数据源选择逻辑
getDataSource方法实现了核心的数据源选择逻辑:
- 如果dsKey为空,则使用主数据源(primary)。
- 如果dsKey对应一个分组数据源,则使用该分组的路由策略选择具体数据源。
- 如果dsKey对应一个具体数据源,则直接使用该数据源。
- 如果strict模式为true且未找到对应数据源,则抛出异常;否则使用主数据源。
public DataSource getDataSource(String ds) {
if (DsStrUtils.isEmpty(ds)) {
return determinePrimaryDataSource();
} else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return groupDataSources.get(ds).determineDataSource();
} else if (dataSourceMap.containsKey(ds)) {
log.debug("dynamic-datasource switch to the datasource named [{}]", ds);
return dataSourceMap.get(ds);
}
if (strict) {
throw new CannotFindDataSourceException("dynamic-datasource could not find a datasource named " + ds);
}
return determinePrimaryDataSource();
}
3. 主数据源选择
determinePrimaryDataSource方法用于选择主数据源,优先检查主数据源名称是否对应一个分组,若否,则直接使用主数据源名称对应的具体数据源。
private DataSource determinePrimaryDataSource() {
log.debug("dynamic-datasource switch to the primary datasource");
DataSource dataSource = dataSourceMap.get(primary);
if (dataSource != null) {
return dataSource;
}
GroupDataSource groupDataSource = groupDataSources.get(primary);
if (groupDataSource != null) {
return groupDataSource.determineDataSource();
}
throw new CannotFindDataSourceException("dynamic-datasource can not find primary datasource");
}
分组数据源
dynamic-datasource支持将多个数据源划分为一个组,通过分组名称可以路由到该组中的某个数据源。分组的实现主要通过以下机制:
数据源名称约定
数据源名称采用"分组名_数据源名"的格式,例如"master_0"、"master_1"、"slave_0"等。系统通过下划线分割来识别分组。
分组数据源创建
在添加数据源时,系统会自动检查数据源名称是否包含下划线,如果包含,则将其添加到对应的分组中:
private void addGroupDataSource(String ds, DataSource dataSource) {
if (ds.contains(UNDERLINE)) {
String group = ds.split(UNDERLINE)[0];
GroupDataSource groupDataSource = groupDataSources.get(group);
if (groupDataSource == null) {
try {
groupDataSource = new GroupDataSource(group, strategy.getDeclaredConstructor().newInstance());
groupDataSources.put(group, groupDataSource);
} catch (Exception e) {
throw new RuntimeException("dynamic-datasource - add the datasource named " + ds + " error", e);
}
}
groupDataSource.addDatasource(ds, dataSource);
}
}
路由策略配置
dynamic-datasource允许通过配置文件自定义路由策略。默认情况下,系统使用LoadBalanceDynamicDataSourceStrategy作为路由策略。
@Setter
private Class<? extends DynamicDataSourceStrategy> strategy = LoadBalanceDynamicDataSourceStrategy.class;
开发者可以通过以下方式修改默认的路由策略:
spring:
datasource:
dynamic:
strategy: com.baomidou.dynamic.datasource.strategy.RandomDynamicDataSourceStrategy
路由流程总结
为了更直观地理解dynamic-datasource的数据源路由流程,我们可以用以下流程图表示:
总结
dynamic-datasource通过灵活的数据源路由规则,为Spring Boot应用提供了强大的多数据源管理能力。本文详细介绍了dynamic-datasource的核心路由组件、路由策略接口、内置路由策略、数据源路由流程以及分组数据源的实现机制。
通过合理配置和使用这些路由规则,开发者可以轻松实现主从分离、读写分离等高级数据源管理功能,满足不同业务场景的需求。
希望本文能够帮助开发者更好地理解和应用dynamic-datasource的数据源路由功能,为构建高性能、高可用的应用系统提供有力支持。
如果您对dynamic-datasource的使用还有其他疑问,欢迎查阅官方文档或参与社区讨论。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



