SpringBoot配置多个数据源

文章介绍了在SpringBoot应用中如何配置和使用Druid数据源,包括主从库的设置,并通过AOP和自定义注解实现读写分离,控制器或方法级别选择不同的数据源。此外,还提到了SpringBootApplication的配置调整以排除默认数据源配置。

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

1. 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
</dependency>

2. 配置

这里只贴出了数据源的配置,其他的配置自行考虑

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: org.postgresql.Driver
        druid:
            # 主库数据源
            master:
                url: 
                username: 
                password: 
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: true
                url: 
                username: 
                password: 

3. 数据源的配置类

  1. 先将数据源注入
@Configuration
public class DruidConfig
{
    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource masterDataSource(DruidProperties druidProperties)
    {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.slave")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    public DataSource slaveDataSource(DruidProperties druidProperties)
    {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }
}
  1. 创建枚举将声明两个数据源
public enum DataSourceType
{
    /**
     * 主库
     */
    MASTER,

    /**
     * 从库
     */
    SLAVE
}
  1. 新建一个类动态的管理数据源
@Primary
@Component
public class DynamicDataSource extends AbstractRoutingDataSource
{
    public static ThreadLocal<String> flag = new ThreadLocal<>();

    @Resource
    private DataSource masterDataSource;

    @Resource
    private DataSource slaveDataSource;

    public DynamicDataSource(){
        flag.set(DataSourceType.MASTER.name());
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return flag.get();
    }

    @Override
    public void afterPropertiesSet() {
        Map<Object, Object> targetDataSource = new ConcurrentHashMap<>();
        targetDataSource.put(DataSourceType.MASTER.name(), masterDataSource);
        targetDataSource.put(DataSourceType.SLAVE.name(), slaveDataSource);
        super.setTargetDataSources(targetDataSource);
        super.setDefaultTargetDataSource(masterDataSource);
        super.afterPropertiesSet();
    }
}
  1. SpringBootApplication的配置
    关闭spring boot自动分配数据源的功能
    @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }),

并开启切面 @EnableAspectJAutoProxy

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableScheduling
@EnableAspectJAutoProxy
public class SpringBootApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(SpringBootApplication.class, args);
    }
}

4. 创建切面和注解

  1. 新建注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    DataSourceType value() default DataSourceType.MASTER;
}
  1. 新建类作为切面,用来处理被注解的方法或者类
@Component
@Aspect
@Slf4j
public class DataSourceAspect {


    @Before("@within(TargetDataSource) || @annotation(TargetDataSource)")
    public void beforeNoticeUpdateDataSource(JoinPoint joinPoint){
        TargetDataSource annotation = null;
        Class<? extends Object> target = joinPoint.getTarget().getClass();
        if(target.isAnnotationPresent(TargetDataSource.class)){
            // 判断类上是否标注着注解
            annotation = target.getAnnotation(TargetDataSource.class);
            log.info("类上标注了注解");
        }else{
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            if(method.isAnnotationPresent(TargetDataSource.class)){
                // 判断方法上是否标注着注解,如果类和方法上都没有标注,则报错
                annotation = method.getAnnotation(TargetDataSource.class);
                log.info("方法上标注了注解");
            }else{
                throw new RuntimeException("@TargetDataSource注解只能用于类或者方法上, 错误出现在:[" +
                        target.toString() +" " + method.toString() + "];");
            }
        }
        // 切换数据源
        DynamicDataSource.flag.set(annotation.value().name());
    }
}

5.注解的使用

  1. 可以在Controller上使用,这样该controller下所有的方法都调用指定的数据库
    因为在创建注解的时候声明的默认值,所以不传值的时候使用默认值指定的数据源
@RestController
@RequestMapping("/test")
@TargetDataSource
public class TestController {
//具体的逻辑
}
  1. 可以在方法上使用,指定只是该方法调用指定的数据库
    用value指定使用的数据源
public class test {
	@Override
	@TargetDataSource(value = DataSourceType.SLAVE)
	public void onLogoutSuccess() {
	        //逻辑
	}
}
  1. 需要说明的是:每一个controller都要加上注解,不然系统会识别不到数据源
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值