SpringBoot的多数据源配置

本文详细介绍了如何在Spring框架中实现动态数据源切换,通过枚举类定义数据库类型,使用AspectJ切面编程在不同数据源间切换,以及配置Druid连接池优化数据库连接管理。

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

一、枚举类

这里面写了要用的数据库

public enum DatabaseType {
    demo_cangku1,
    demo_cangku2
}

 

二、动态数据源

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<DataSourceType>();

    public static void setDataSourceType(DataSourceType dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static DataSourceType getDataSourceType() {
        return contextHolder.get();
    }

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

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

 

三、数据源配置

import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;


@Configuration
@EnableTransactionManagement                // 启用事务
public class DruidDBConfig {

    final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 设置数据源
     *
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@Aautowire注解报错
     * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource(
            @Value("${spring.datasource.primary.url}") String primaryUrl,
            @Value("${spring.datasource.primary.username}") String primaryUsername,
            @Value("${spring.datasource.primary.password}") String primaryPassword,

            @Value("${spring.datasource.secondary.url}") String secondaryUrl,
            @Value("${spring.datasource.secondary.username}") String secondaryUsername,
            @Value("${spring.datasource.secondary.password}") String secondaryPassword

            ) {

        //数据源-1
        DruidDataSource primaryDataSource = getDruidDataSource();
        primaryDataSource.setUrl(primaryUrl);
        primaryDataSource.setUsername(primaryUsername);
        primaryDataSource.setPassword(primaryPassword);
        //数据源-2
        DruidDataSource secondaryDataSource = getDruidDataSource();
        secondaryDataSource.setUrl(secondaryUrl);
        secondaryDataSource.setUsername(secondaryUsername);
        secondaryDataSource.setPassword(secondaryPassword);

        Map<Object, Object> mapDataSources = new HashMap<>();
        mapDataSources.put(DataSourceType.demo_cangku1, primaryDataSource);
        mapDataSources.put(DataSourceType.demo_cangku2, secondaryDataSource);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(mapDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认的datasource设置为primaryDataSource
        return dataSource;
    }

    //配置事务管理器
    @Bean("txManager")
    public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }


    @Value("${spring.datasource.initialSize}")
    private Integer initialSize;

    @Value("${spring.datasource.minIdle}")
    private Integer minIdle;

    @Value("${spring.datasource.maxActive}")
    private Integer maxActive;

    @Value("${spring.datasource.maxWait}")
    private Integer maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private Long timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private Long minEvictableIdleTimeMillis;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.testWhileIdle}")
    private Boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private Boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private Boolean testOnReturn;

    @Value("${spring.datasource.poolPreparedStatements}")
    private Boolean poolPreparedStatements;

    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private Integer maxPoolPreparedStatementPerConnectionSize;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("${spring.datasource.connectionProperties}")
    private String connectionProperties;

    @Value("${spring.datasource.useGlobalDataSourceStat}")
    private Boolean useGlobalDataSourceStat;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;

    private DruidDataSource getDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setInitialSize(initialSize);
        druidDataSource.setMinIdle(minIdle);
        druidDataSource.setMaxActive(maxActive);
        druidDataSource.setMaxWait(maxWait);
        druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        druidDataSource.setValidationQuery(validationQuery);
        druidDataSource.setTestWhileIdle(testWhileIdle);
        druidDataSource.setTestOnBorrow(testOnBorrow);
        druidDataSource.setTestOnReturn(testOnReturn);
        druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            druidDataSource.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        druidDataSource.setConnectionProperties(connectionProperties);
        druidDataSource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
        druidDataSource.setDriverClassName(driverClassName);
        return druidDataSource;
    }
}

application.yml数据源参数配置

spring:
  application:
    name: callCollectionSystemService
    index: 1
  profiles:
    active: local
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    minIdle: 5
    maxActive: 50
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j2
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    useGlobalDataSourceStat: true
  messages:
    basename: messages/messages

 

四、数据源切面

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

@Aspect//使用@Aspect注解将一个java类定义为切面类
@Order(5)
@Configuration
public class DataSourceAop {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("execution(public * com.test.CallCollectionSystemService.dao.demo_cangku1..*.*(..))")
    public void demo_cangku1() {
    }

    @Before("cangku1()")
    public void cangku1_doBefore(JoinPoint joinPoint) throws Throwable {
        if(null == DynamicDataSource.getDataSourceType() || !DynamicDataSource.getDataSourceType().equals(DataSourceType.demo_cangku1)) {
            DynamicDataSource.setDataSourceType(DataSourceType.demo_cangku1);
        }
    }

    @Pointcut("execution(public * com.test.CallCollectionSystemService.dao.cangku2..*.*(..))")
    public void cangku2() {
    }

    @Before("cangku2()")
    public void cangku2_doBefore(JoinPoint joinPoint) throws Throwable {
        if(null == DynamicDataSource.getDataSourceType() || !DynamicDataSource.getDataSourceType().equals(DataSourceType.cangku2)) {
            DynamicDataSource.setDataSourceType(DataSourceType.cangku2);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值