多数据源配置

1.配置项(数据库驱动省略)
1.1 bootstrap-local.yml
server:
  port: 7700
spring:
  datasource:
#    思源eop库(描述:超管)
    siyuaneApp:
      url: xx
      username:  x x x x
      password:  sa
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    siyuaneop:
      url:  x x x x
      username: sa
      password: x x
      driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: x x x x
      username: x x
      password: xx
management:
  endpoints:
    web:
      exposure:
        include: '*'
#mybatis
mybatis:
  config-location: classpath:mybatis-config.xml
  mapper-locations: classpath:/mapper/*.xml
logging:
  level:
    com.alibaba.nacos.client.naming: WARN
1.2 配置数据源DynamicDataSourceConfig
package com.pipe.system.dynamicdatasource.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.pipe.system.dynamicdatasource.DynamicDataSource;
import com.pipe.system.dynamicdatasource.constant.DataSourceConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

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

/**
 * @author lds
 * @date 2023/8/1
 * @Desc 
 */
@Slf4j
@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class , DruidDataSourceAutoConfigure.class})
public class DynamicDataSourceConfig {
    @Resource
    private DataSourcePropertiesConfig dataSourcePropertiesConfig;
    private DataSource dataSource(DataSourceProperties dataSourceProperties){
        return DataSourceBuilder.create()
                .driverClassName(dataSourceProperties.getDriverClassName())
                .url(dataSourceProperties.getUrl())
                .username(dataSourceProperties.getUsername())
                .password(dataSourceProperties.getPassword())
                .build();
    }
  /**
  动态读取nacos 配置文件中数据库配置项
  */
    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        Map<Object, Object> dataSourceMap = new HashMap<>(16);
        log.info("dataSourcePropertiesConfig: {}",dataSourcePropertiesConfig);
        Map<String, DataSourceProperties> dataSourcePropertiesMap = dataSourcePropertiesConfig.getDataSourceConfig();
        dataSourcePropertiesMap.forEach((merchant, properties) -> dataSourceMap.put(merchant, dataSource(properties)));
        // 设置动态数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(dataSourceMap.get(DataSourceConstants.DS_KEY_MASTER));
        log.info("动态数据源dynamicDataSource: {}",dynamicDataSource);
        return dynamicDataSource;
    }
    @Primary
    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dynamicDataSource());
    }
}

1.3 动态数据源选择上下文DynamicDataSourceContextHolder
package com.pipe.system.dynamicdatasource;

import com.pipe.system.dynamicdatasource.constant.DataSourceConstants;

/**
 * @author lds
 * @date 2023/8/1
 * @Desc
 */
public class DynamicDataSourceContextHolder {
    /**
     * 动态数据源名称上下文
     */
    private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();
    /**
     * 设置/切换数据源
     */
    public static void setContextKey(String key){
        DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
    }
    /**
     * 获取数据源名称
     */
    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();
    }
}
1.4 设置DynamicDataSource路由策略
package com.pipe.system.dynamicdatasource;

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

/**
 * @author lds
 * @date 2023/8/1
 * @Desc
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getContextKey();
    }
}
1.5 动态读取nacos配置中心数据库配置DataSourcePropertiesConfig
package com.pipe.system.dynamicdatasource.config;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import java.util.*;

/**
 * @author lds
 * @date 2023/8/2
 * @Desc
 */
@Slf4j
@RefreshScope
@ConfigurationProperties(prefix = DataSourcePropertiesConfig.PREFIX)
public class DataSourcePropertiesConfig {
    public static final String PREFIX = "spring";
    /**
     * 数据库配置
     */
    @Setter
    private Map<String, Map<String,String>> datasource;

    /**
     * 动态读取nacos配置中心数据库配置
     * @return
     */
    public Map<String, DataSourceProperties> getDataSourceConfig() {
        Map<String, DataSourceProperties> resultMap = new HashMap<>(16);
        datasource.forEach((merchant, setConfig) -> {
            DataSourceProperties dataSourceProperties = DataSourceProperties.builder()
                                            .driverClassName(setConfig.get("driver-class-name"))
                                            .url(setConfig.get("url"))
                                            .username(setConfig.get("username"))
                                            .password(setConfig.get("password")).build();
                log.info("nacos配置文件数据库配置 :{}",dataSourceProperties);
            resultMap.put(merchant, dataSourceProperties);
        });
        log.info("多数据源最终map :{}",resultMap);
        return resultMap;
    }
}
1.6 数据库连接属性DataSourceProperties
@Data
@Builder
public class DataSourceProperties {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
}
1.7 constants
public interface DataSourceConstants {
    String DS_KEY_MASTER = "druid";
}
2.动态数据源注解切面
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
    /**
     * 数据源名称
     */
    String value() default DataSourceConstants.DS_KEY_MASTER;
}
package com.pipe.system.dynamicdatasource.aspect;
import com.pipe.system.dynamicdatasource.DynamicDataSourceContextHolder;
import com.pipe.system.dynamicdatasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @author lds
 * @date 2023/8/1
 * @Desc 多数据源切面配置
 */
@Slf4j
@Component
@Aspect
public class DynamicDataSourceAspect {
    /**
     * 切@DS注解
     */
    @Pointcut("@annotation(com.pipe.system.dynamicdatasource.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();
        }
    }

    /**
     * 根据类或方法获取数据源注解
     */
    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);
        }
    }
}
3.使用
@Slf4j
@RestController
@RequestMapping("/v1.0/slaver")
public class SalverContoller {
    @Autowired
    private JdbcTemplate jdbcTemplate;
		/**
		可在service使用 @DS动态切换数据源 
		*/
    @PostMapping("/nologin/sendSms")
    @DS("siyuaneop")
    public CommonResult sendSms() {
        //切换数据源,在slave查询
        List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from table where  mobile = 'xxxx'");
        System.out.println("list");
        return CommonResult.success(list);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值