记一次配置SpringBoot多数据源

本文介绍了如何在Spring Boot中配置主从数据库,并通过动态数据源实现数据源的切换。配置包括了数据库连接信息,动态数据源的创建,以及使用AOP注解实现方法级别的数据源选择。在实际应用中,通过自定义`@DS`注解,可以在方法上指定使用哪个数据源,从而灵活地在主库和从库之间切换。
摘要由CSDN通过智能技术生成

1.数据库连接信息配置

#master数据库
spring.datasource.druid.master.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.master.jdbc-url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.druid.master.username=root
spring.datasource.druid.master.password=root
#slave数据库
spring.datasource.druid.slave.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.druid.slave.jdbc-url=jdbc:oracle:thin:@127.0.0.1:1521/orcl
spring.datasource.druid.slave.username=wbs
spring.datasource.druid.slave.password=wbs

2.动态数据源配置

@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@Configuration
@MapperScan(basePackages = "com.**.dao.mapper")
public class DataSourceConfig {

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

    @Bean(DataSourceConstants.DS_KEY_SLAVE)
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<Object, Object> dataSourceMap = new HashMap<>(2);
        dataSourceMap.put(DataSourceConstants.DS_KEY_MASTER, masterDataSource());
        dataSourceMap.put(DataSourceConstants.DS_KEY_SLAVE, slaveDataSource());
        //设置动态数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
        return dynamicDataSource;
    }

}
/**
 * 动态数据源
 *
 * @author: haojl
 * @since: 2022/3/23
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getContextKey();
    }
}

3.动态选择数据源

/**
 * 动态数据源名称上下文处理
 **/
public class DynamicDataSourceContextHolder {

    /**
     * 动态数据源名称上下文
     */
    private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源
     * @param key
     */
    public static void setContextKey(String key){
        System.out.println("切换数据源"+key);
        DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
    }

    /**
     * 获取数据源名称
     * @return
     */
    public static String getContextKey(){
        String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
        return key == null?DataSourceConstants.DS_KEY_MASTER:key;
    }

    /**
     * 删除当前数据源名称
     */
    public static void removeContextKey(){
        DATASOURCE_CONTEXT_KEY_HOLDER.remove();
    }
}
/**
 * 数据源常量
 **/
public class DataSourceConstants {
    /**
     * master数据源
     */
    public static final String DS_KEY_MASTER = "master";
    /**
     * slave数据源
     */
    public static final String DS_KEY_SLAVE = "slave";
}

4.使用 AOP 选择数据源

定义数据源注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DS {
    String value() default DataSourceConstants.DS_KEY_MASTER;
}

定义数据源切面

@Aspect
@Component
@Order(-100)
public class DynamicDataSourceAspect {
    private  static final Logger loger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    @Pointcut("@annotation(com.lhzw.platform.core.common.aop.annotation.DS)")
    public void dataSourcePointCut(){

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String dsKey = getDSAnnotation(joinPoint).value();
        DynamicDataSourceContextHolder.setContextKey(dsKey);
        try{
            return joinPoint.proceed();
        }finally {
            DynamicDataSourceContextHolder.removeContextKey();
        }
    }

    /**
     * 根据类或方法获取数据源注解
     * @param joinPoint
     * @return
     */
    private DS getDSAnnotation(ProceedingJoinPoint joinPoint){
        Class<?> targetClass = joinPoint.getTarget().getClass();
        DS dsAnnotation = targetClass.getAnnotation(DS.class);
        // 先判断类的注解,再判断方法注解
        if(Objects.nonNull(dsAnnotation)){
            return dsAnnotation;
        }else{
            MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
            return methodSignature.getMethod().getAnnotation(DS.class);
        }
    }
}

5.使用自定义注解进行数据源切换

	@DS(DataSourceConstants.DS_KEY_SLAVE)
    @Override
    public List<Map<String, Object>> list() {
        return testOrclMapper.list();
    }

    @Override
    public List<Map<String, Object>> list1() {
        return testOrclMapper.list1();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值