springboot中Druid多数据源配置

本文详细介绍了SpringBoot中如何配置Druid以实现多数据源管理,包括application.properties的设置、数据源加载、动态数据源配置、数据源路由、注解配置以及切面配置等关键步骤。

1.application.properties配置如下:

#数据源1
spring.jdbc.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.jdbc.datasource.ds1.url=jdbc:mysql://localhost:3306/test?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.jdbc.datasource.ds1.username=root
spring.jdbc.datasource.ds1.password=root
spring.jdbc.datasource.ds1.type = com.alibaba.druid.pool.DruidDataSource

###########################################################
#数据源2
spring.jdbc.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.jdbc.datasource.ds2.url=jdbc:mysql://localhost:3307/test?zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.jdbc.datasource.ds2.username=root
spring.jdbc.datasource.ds2.password=root
spring.jdbc.datasource.ds2.type = com.alibaba.druid.pool.DruidDataSource

2.加载数据源

@Configuration
@Slf4j
public class DataSourceConfig {
    @Bean("springDataSource1")
    @ConfigurationProperties("spring.jdbc.datasource.ds1")
    public DataSource springDataSource(){
        DataSource dataSource  = DruidDataSourceBuilder.create().build();
        return dataSource;
    }

    @Bean("springDataSource2")
    @ConfigurationProperties("spring.jdbc.datasource.ds2")
    public DataSource springDataSource(){
        DataSource dataSource  = DruidDataSourceBuilder.create().build();
        return dataSource;
    }
}

3.动态数据源配置

@Configuration
public class DynamicTransactionManager {

    @Autowired
    @Qualifier("springDataSource1")
    private DataSource springDataSource1;

    @Autowired
    @Qualifier("springDataSource2")
    private DataSource springDataSource2;

    @Bean
    public DynamicDataSource dataSource(){
        //按照目标数据源名称和目标数据源对象的映射存放在Map中
        Map<Object,Object> targetDataSources = new HashMap<>();
        targetDataSources.put("springDataSource1",springDataSource1);
        targetDataSources.put("springDataSource2",springDataSource2);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        //设置默认的数据源,当拿不到数据源时,使用此配置
        dataSource.setDefaultTargetDataSource(springDataSource1);
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager txManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

4.动态数据源路由

public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * 数据源路由,此方法用于产生要选取的数据源逻辑名称
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        //从共享线程中获取数据源名称
        return DynamicDataSourceHolder.getDataSource();
    }
}
public class DynamicDataSourceHolder {
    /**
     * 本地线程共享对象
     */
    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();

    public static void putDataSource(String name){
        THREAD_LOCAL.set(name);
    }

    public static String getDataSource(){
        return THREAD_LOCAL.get();
    }

    public static void removeDataSource(){
        if(THREAD_LOCAL.get() != null)
            THREAD_LOCAL.remove();
    }
}

5.配置注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {
    String value() default "shardingDataSource";    //此处接收的是数据源名称
}

6.配置切面

@Component
@Aspect
@Order(1)
@Slf4j
public class DataSourceAspect {
    //切换放在mapper接口的方法上,所以这里要配置AOP切面的切入点
    @Pointcut("@annotation(TargetDataSource)")
    public void dataSourcePointCut(){

    }
    @Before("dataSourcePointCut()")
    public void before(JoinPoint joinPoint){
        Object target = joinPoint.getTarget();
        String method = joinPoint.getSignature().getName();
        Class<?> clazz = target.getClass();
        Class<?>[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
        try{
            Method m = clazz.getMethod(method,parameterTypes);
            //如果方法上存在切换数据源的注解,则根据注解内容进行数据源切换
            if(m!=null && m.isAnnotationPresent(TargetDataSource.class) && DynamicDataSourceHolder.getDataSource() == null){
                TargetDataSource data = m.getAnnotation(TargetDataSource.class);
                String dataSourceName = data.value();

                DynamicDataSourceHolder.putDataSource(dataSourceName);
                log.debug("current thread "+Thread.currentThread().getName()+" add data to ThreadLocal");
            }else{
                log.debug("switch datasource fail, use default");
            }
        }catch (Exception e){
            log.error("current thread "+Thread.currentThread().getName()+" add data to ThreadLocal error",e);
        }
    }

    //执行完切面后,将线程共享中的数据源名称清空
    @After("dataSourcePointCut()")
    public void after(JoinPoint joinPoint){
        DynamicDataSourceHolder.removeDataSource();
    }
}

 

### Spring Boot与Druid组合使用实现多数据源配置 #### 一、引入依赖 为了支持多数据源功能,需在`pom.xml`文件中添加特定的starter来简化集成过程[^2]。 对于Maven项目而言: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>x.x.x</version><!-- 版本号依据实际需求 --> </dependency> ``` Gradle项目则如下所示: ```groovy implementation 'com.baomidou:dynamic-datasource-spring-boot-starter:x.x.x' //版本号依据实际需求填写 ``` #### 二、定义主数据源bean 通过自定义方法创建并返回一个名为`dataSource()`的数据源实例对象。此部分展示了如何利用@ConfigurationProperties注解绑定属性至相应字段上,并初始化DruidDataSource类型的组件[^1]。 ```java import com.alibaba.druid.pool.DruidDataSource; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @ConfigurationProperties("spring.datasource.primary") @Bean(name = "primaryDataSource") public DruidDataSource primaryDataSource(){ DruidDataSource druidDataSource=new DruidDataSource(); //可在此处进一步定制化druid参数... return druidDataSource ; } ``` #### 三、扩展其他次级数据源beans 除了默认提供给应用程序使用的单一数据库连接池外,还可以按照相同模式继续声明额外的数据源bean以满足不同业务逻辑下的访问需求。这里假设存在第二个数据源secondaryDataSource[]^1]。 ```java @ConfigurationProperties("spring.datasource.secondary") @Bean(name="secondaryDataSource") public DruidDataSource secondaryDataSource(){ DruidDataSource druidDataSource= new DruidDataSource(); //同样可以针对该数据源做个性化调整... return druidDataSource ; } ``` #### 四、注册动态切换策略 为了让程序能够在运行期间灵活地选择合适的目标数据源执行查询操作,还需要编写一段用于管理这些资源间转换关系的小工具类。它通常会继承AbstractRoutingDataSource抽象父类重写其determineCurrentLookupKey()函数完成具体判定流程[^3]。 ```java @Component public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); @Override protected Object determineCurrentLookupKey() { return getContext(); } public void setContext(String dbType){ contextHolder.set(dbType); } public String getContext(){ return Optional.ofNullable(contextHolder.get()).orElse("default"); } } ``` 最后一步就是把之前准备好的各个独立单元组装起来形成完整的解决方案框架了。这涉及到修改application.yml(application.properties)中的相关设定项以及确保所有必要的Java Config已经就位以便于容器能够自动识别加载它们[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值