springboot多数据源的原理

欢喜 SpringBoot 发布时间:2025-06-04 14:10:12 阅读数:1821 1
下文笔者讲述SpringBoot多数据源的原理简介说明,如下所示

SpringBoot多数据源原理

Spring Boot多数据源原理
   主要依赖于 
      动态数据源切换机制
    和 自定义 `AbstractRoutingDataSource`
多数据源的具体实现思路:
    根据业务逻辑在运行时选择不同的数据源

SpringBoot多数据源核心原理

1.`AbstractRoutingDataSource`
- Spring提供抽象类 `AbstractRoutingDataSource`
     它是一个基于 lookup key 动态决定使用哪个目标数据源的路由类。
- 它内部维护了一个`targetDataSources`
     映射(`Map<Object, DataSource>`)
	  通过一个`determineCurrentLookupKey()`方法
	   来决定当前线程使用数据源key
	    
public abstract class AbstractRoutingDataSource extends AbstractDataSource {
    private Map<Object, DataSource> targetDataSources;
    private DataSource defaultTargetDataSource;

    protected abstract Object determineCurrentLookupKey();
}

2.使用 ThreadLocal 存储当前线程的数据源标识
- 为了实现多线程环境下的数据源隔离
    通常会用`ThreadLocal`来保存当前线程的数据源标识(如 `master`, `slave1`, `slave2`)
- 在 AOP 或拦截器中设置该标识
    在`determineCurrentLookupKey()`中读取
 
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSourceType(String type) {
        CONTEXT_HOLDER.set(type);
    }

    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }

    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}
 
3.配置多个数据源 Bean
- 手动配置多个 `DataSource` Bean
    并将它们注入到 `AbstractRoutingDataSource` 
	  的 `targetDataSources` 中。
- 设置默认数据源 `defaultTargetDataSource`。

4. AOP/拦截器控制数据源切换
- 使用切面或拦截器,在进入方法前设置数据源标识。
- 例:
    根据注解 `@DataSource("slave1")` 自动切换。

SpringBoot多数据源流程图

1.请求进来
2.AOP 拦截方法,判断是否有 `@DataSource` 注解
3.如果有,
    调用`DynamicDataSourceContextHolder.setDataSourceType("xxx")`
4.Spring调用
   `determineCurrentLookupKey()`获取当前数据源 key
5.根据key
    从`targetDataSources`中获取对应的实际`DataSource`
6.数据库操作使用该数据源执行 SQL
7.请求结束,清理 ThreadLocal 中的数据源标识
 
 1.自定义数据源类
 
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}
  
 2.配置类
 
@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave1")
    public DataSource slave1DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DataSource dynamicDataSource(DataSource masterDataSource, DataSource slave1DataSource) {
        DynamicDataSource ds = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave1", slave1DataSource);
        ds.setTargetDataSources(targetDataSources);
        ds.setDefaultTargetDataSource(masterDataSource); // 默认数据源
        return ds;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }
}
 
 3.切面控制切换
 
@Aspect
@Component
public class DataSourceAspect {

    @Pointcut("@annotation(dataSource)")
    public void dataSourcePointCut(DataSourceAnnotation dataSource) {}

    @Around("dataSourcePointCut(dataSource)")
    public Object around(ProceedingJoinPoint point, DataSourceAnnotation dataSource) throws Throwable {
        String dsKey = dataSource.value();
        DynamicDataSourceContextHolder.setDataSourceType(dsKey);
        try {
            return point.proceed();
        } finally {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }
}

4.自定义注解
 
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.Runtime)
public @interface DataSourceAnnotation {
    String value();
}

SpringBoot多数据源注意事项

事项 说明
事务管理 动态数据源不支持跨数据源事务(XA 除外)
线程安全 必须使用 ThreadLocal,避免线程复用问题(如线程池)
默认数据源 建议设置一个默认数据源,防止未设置key导致异常
性能影响 切换本身性能开销小,但频繁切换可能影响可读性和调试
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/SpringBoot/202506/8467.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者