springboot多数据源的配置方法

springboot多数据源的配置方法

方法一:自己动手写原生

springboot有时候会使用到多数据源,比如mysql、oracle同时使用,或者其他数据库;
大体思路是这么样呢?
springboot多数据源的配置方法_第1张图片
思路:在yml里面配置两个数据源(这里以两个为例,也可以配多个数据源),在DataSourceContextHolder配置,一个默认数据源,还有就是其他数据源,当使用注解时(自定义注解),把指定的要使用的数据源注入使用,不使用注解就取默认的注解。
第一步:写个枚举方便取数据源

/**
 * 枚举,区分数据源
 */
public enum DataSourceEnum {
    DB1("db1"),
    DB2("db2");
    private String value;
    
    DataSourceEnum(String value){
        this.value=value;
    }
    public String getValue(){
        return value;
    }
}

第二步:创建一个线程安全的DatabaseType,存放数据源

/**
 * 保存一个线程安全的DatabaseType容器
 * @author Admin
 * @Date 2020/04/19
 */
public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();

    public static String getDataSource() {
        return contextHolder.get();
    }
    public static void setDataSource(DataSourceEnum dataSource){
        contextHolder.set(dataSource.getValue());
    }
    public static void clear(){
        contextHolder.remove();
    }
}

第三步:写一个获取数据源的类

/**
 * 动态数据源,需要继承AbstractRoutingDataSource
 * 作用:使用DatabaseContextHolder获取当前线程的DatabaseType
 * @author Admin
 */
public class MultipleDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

第四步(最核心):初始化数据源,并设置默认数据源

/**
 * springboot集成mybatis基本入口
 * 1.创建数据源
 * 2.创建sqlsessionFactory
 * @author Admin
 */
@Configuration
public class MybatisPlusConfiguration {
    /**
     * @ConfigurationProperties 的大致作用就是:赋值,将注解转换成对象。给对象赋值
     * @return
     */
    @Bean(name="db1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db1")
    public DataSource db1(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean(name="db2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db2")
    public DataSource db2(){
        return DruidDataSourceBuilder.create().build();
    }
    /**
     * 创建动态数据源
     * @primary: 表示在同一个接口有多个类可以注入的时候,默认选择哪个,而不是让@Autowire报错,spring扫码注入bean时优先注入带有@Primary注解的bean
     *@Qualifier:
     * 当有多个同一类型的Bean时,可以用@Qualifier(“name”)来指定。@Qualifier限定描述符除了能根据名字进行注入,还能进行更细粒度的控制如何选择候选者
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
                                         @Qualifier("db2") DataSource db2){
        MultipleDataSource dataSource = new MultipleDataSource();

        Map<Object,Object> targetDataSource = new HashMap<>();

        targetDataSource.put(DataSourceEnum.DB1.getValue(),db1);
        targetDataSource.put(DataSourceEnum.DB2.getValue(),db2);
        System.out.println("我是目标数据源:"+targetDataSource);
        dataSource.setTargetDataSources(targetDataSource);
        /**
         *  setDefaultTargetDataSource:当不加注解时,就取默认的数据源
         *  在这里设置默认数据源
         */
        dataSource.setDefaultTargetDataSource(db1);
        System.out.println("我是最终数据源:"+dataSource.determineCurrentLookupKey());
        return dataSource;
    }
}

至此,可以取默认数据源了,也就是不写注解的(前提是配置了yml)
第五步:写自定义注解

/**
 * 数据源注解
 * @author Admin
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    DataSourceEnum value() default DataSourceEnum.DB1;
}

第六步:注解的切面

/**
 *  @author Admin
 * @Order(-1)保证该AOP在@Transactional之前执行,如果没有order,而且类配置了@Transaction那么数据源会失效
 *  通过order指定顺序,值越小越先执行,不标注数字则默认int最大值2147483647,即优先级最低
 */
@Component
@Aspect
@Order(-1)
@Slf4j
public class DataSourceAspect {

    @Pointcut("@annotation(com.sinux.liaochao.multidatasource.multipartidatasource.config.DataSource)")
    public void pointCut(){

    }
    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println("我是注解切面:=================================================");
        Object target = joinPoint.getTarget();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        DataSourceEnum dataSource = null;
        try {
            Method method = target.getClass().getMethod(signature.getName(),signature.getParameterTypes());
            if(method.isAnnotationPresent(DataSource.class)){
                DataSource annotation = method.getAnnotation(DataSource.class);
                 dataSource =  annotation.value();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        log.info("选择数据源========",dataSource.getValue());
        DataSourceContextHolder.setDataSource(dataSource);
    }
    @After("pointCut()")
    public void doAfter(){
        DataSourceContextHolder.clear();
    }
}

自此主业完成。
第七步:配置yml

spring:
  application:
  name: multiDatasource
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      db1:
        url: jdbc:mysql://192.168.61.147:3306/tensquare_article?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
        username: root
        password: 123456
      db2:
        url: jdbc:mysql://192.168.61.148:3306/tensquare_article?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
        username: root
        password: 123456

代码中使用:(只举一个例子 @DataSource(DataSourceEnum.DB2)表示使用db2数据源

不配注解或者配DataSourceEnum.DB1都是使用数据源1,因为dataSource.setDefaultTargetDataSource(db1);设置默认为db1)

 /**
     * 查询数据源2的内容
     * @return
     */
    @Override
    @DataSource(DataSourceEnum.DB2)
    public CommonResult<JSONObject> queryDB2() {
        List<JSONObject> list = multipartiDataSourceMapper.queryDB2();
        JSONObject js = new JSONObject();
        js.put("list",list);
        js.put("code",200);
        js.put("msg","查询成功!");
        js.put("message","success");
        return CommonResult.success(js);
    }

方法二 mybatis-plus提供注解驱动多数据源

一、导包

<dependency>
  <groupId>com.baomidougroupId>
  <artifactId>dynamic-datasource-spring-boot-starterartifactId>
  <version>1.3.3version>
dependency>

第二步、配置yml

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
          schema: db/schema.sql # 配置则生效,自动初始化表结构
          data: db/data.sql # 配置则生效,自动初始化数据
          continue-on-error: true # 默认true,初始化失败是否继续
          separator: ";" # sql默认分号分隔符
          
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2

第三步:在方法上写注解

使用 @DS 切换数据源。
@DS 可以注解在方法上和类上,同时存在方法注解优先于类上注解。

强烈建议只注解在service实现上
@Service
@DS(“slave”)
public class UserServiceImpl implements UserService {
}

你可能感兴趣的:(java,java,mybatis,spring,boot,aop)