SpringBoot+Druid多数据源配置

本文介绍了如何使用Spring Boot和Druid实现应用中的动态数据源配置,包括引入依赖、配置参数、创建DataSource Bean、设置数据源AOP代理及修改启动文件。通过多数据源注解,可以灵活切换不同的数据库连接,便于测试和部署不同环境的数据访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下内容转载自:https://my.oschina.net/u/3681868/blog/1813011

一, 引入Jar包:

<dependency> <!-- MySql驱动 -->
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
<dependency> <!-- 连接池 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.9</version>
</dependency>

二, 配置参数:

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        druid:
            one:  #数据源1
                url: jdbc:mysql://localhost:3306/test1?...
                username: root
                password: root
            two: #数据源2
                url: jdbc:mysql://localhost:3306/test2?...
                username: root
                password: root
            initial-size: 10
            max-active: 100
            min-idle: 10
            max-wait: 60000
            pool-prepared-statements: true
            max-pool-prepared-statement-per-connection-size: 20
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 300000
            validation-query: SELECT 1 FROM DUAL
            test-while-idle: true
            test-on-borrow: false
            test-on-return: false
            stat-view-servlet:
                enabled: true
                url-pattern: /druid/*
                #login-username: admin
                #login-password: admin
            filter:
                stat:
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true

(参数配置,可参考:  https://gitee.com/wenshao/druid/tree/master/druid-spring-boot-starter)

三, 编写配置文件:

1,  定义数据源名称常量 : 

package com.gy.fast.common.config.data;

/**
 * 数据源名称
 * @author geYang
 * @date 2018-05-14
 */
public interface DataSourceNames {
    String ONE = "ONE";
    String TWO = "TWO";
}

2,  创建动态数据源:

package com.gy.fast.common.config.data;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.Map;

/**
 * 动态数据源
 * @author geYang
 * @date 2018-05-14
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    /**
     * 配置DataSource, defaultTargetDataSource为主数据库
     */
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

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

    public static void clearDataSource() {
        contextHolder.remove();
    }

}

3, 动态数据源配置:

package com.gy.fast.common.config.data;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置多数据源
 * @author geYang
 * @date 2018-05-14
 */
@Configuration
public class DynamicDataSourceConfig {
    
    /**
     * 创建 DataSource Bean
     * */
    
    @Bean
    @ConfigurationProperties("spring.datasource.druid.one")
    public DataSource oneDataSource(){
        DataSource dataSource = DruidDataSourceBuilder.create().build();
        return dataSource;
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.two")
    public DataSource twoDataSource(){
        DataSource dataSource = DruidDataSourceBuilder.create().build();
        return dataSource;
    }
    
    /**
     * 如果还有数据源,在这继续添加 DataSource Bean
     * */
    
    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource oneDataSource, DataSource twoDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>(2);
        targetDataSources.put(DataSourceNames.ONE, oneDataSource);
        targetDataSources.put(DataSourceNames.TWO, twoDataSource);
        // 还有数据源,在targetDataSources中继续添加
        System.out.println("DataSources:" + targetDataSources);
        return new DynamicDataSource(oneDataSource, targetDataSources);
    }
}

4, 定义动态数据源注解:

package com.gy.fast.common.config.data;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 多数据源注解
 * @author geYang
 * @date 2018-05-14
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default DataSourceNames.ONE;
}

5, 设置数据源 AOP 代理:

package com.gy.fast.common.config.data;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 数据源AOP切面处理
 * @author geYang
 * @date 2018-05-14
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 切点: 所有配置 DataSource 注解的方法
     */
    @Pointcut("@annotation(com.gy.fast.common.config.data.DataSource)")
    public void dataSourcePointCut() {}

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource ds = method.getAnnotation(DataSource.class);
        // 通过判断 DataSource 中的值来判断当前方法应用哪个数据源
        DynamicDataSource.setDataSource(ds.value());
        System.out.println("当前数据源: " + ds.value());
        logger.debug("set datasource is " + ds.value());
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

四, 修改启动文件:

package com.gy.fast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;

import com.gy.fast.common.config.data.DynamicDataSourceConfig;


/**
 * 动态数据源配置,需要将自有的配置依赖(DynamicDataSourceConfig),将原有的依赖去除(DataSourceAutoConfiguration)
 * @author geYang
 * @date 2018-05-15
 */
@Import({DynamicDataSourceConfig.class})
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class FastApplication {
	public static void main(String[] args) {
		SpringApplication.run(FastApplication.class, args);
	}
}

五, 配置完成, 进行测试:

package com.gy.fast;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.gy.fast.common.config.data.DataSource;
import com.gy.fast.common.config.data.DataSourceNames;
import com.gy.fast.module.sys.entity.SysUser;
import com.gy.fast.module.sys.service.SysUserService;

/**
 * 测试多数据源
 * @author geYang
 * @date 2018-05-15
 */
@Service
public class DataSourceTestService {
    @Autowired
    private SysUserService sysUserService;

    public SysUser test1(Long userId){
        return sysUserService.selectById(userId);
    }

    @DataSource(DataSourceNames.TWO)
    public SysUser test2(Long userId){
        return sysUserService.selectById(userId);
    }
}
package com.gy.fast;


import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.gy.fast.module.sys.entity.SysUser;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicDataSourceTest {
    @Autowired
    private DataSourceTestService dataSourceTestService;
    
    @Test
    public void test(){
        // 数据源ONE
        SysUser user1 = dataSourceTestService.test1(1L);
        System.out.println(ToStringBuilder.reflectionToString(user1));

        // 数据源TWO
        SysUser user2 = dataSourceTestService.test2(1L);
        System.out.println(ToStringBuilder.reflectionToString(user2));

        // 数据源ONE
        SysUser user3 = dataSourceTestService.test1(1L);
        System.out.println(ToStringBuilder.reflectionToString(user3));
    }
    
}
### Spring BootDruid组合使用实现多数据源配置 #### 一、引入依赖 为了支持多数据源功能,需在`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、付费专栏及课程。

余额充值