AbstractRoutingDataSource,spring配置多数据源问题

AbstractRoutingDataSource,spring配置多数据源问题

首先引入pom.xml依赖

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <version>2.3.12.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
            <version>2.3.12.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.0.1version>
        dependency>
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.1.1version>
        dependency>
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelper-spring-boot-starterartifactId>
            <version>1.2.13version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druid-spring-boot-starterartifactId>
            <version>1.1.18version>
        dependency>

        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-generatorartifactId>
            <version>3.1.1version>
        dependency>

在application.yml中添加配置

spring:
  application:
    name: tms
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    ds1:
      driver-class-name: Driver
      url: ${url}
      username: ${username}
      password: ${password}
    ds2:
      driver-class-name: Driver
      url: ${url}
      username: ${username}
      password: ${password}

其中加了两个数据库配置

添加这两个数据库的配置, 注入到bean

package com.dualdb;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;


@Configuration
public class MyBootDataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.ds1")
    public DataSource dataSource1() {
        // 通过配置地址拿到spring.datasource中的配置,创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.ds2")
    public DataSource dataSource2() {
        // 通过配置地址拿到spring.datasource中的配置,创建一个DruidDataSource
        return DruidDataSourceBuilder.create().build();
    }
}

配置这两个数据源的主从关系, 及切换标识

package com.config.dualdb;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

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

@Component
@Primary // 有多个datasource时,将此source设置为主要注入的bean,primary
public class DynamicDatasource extends AbstractRoutingDataSource {

    // 数据源标识,为了保证线程安全使用threadLocal
    public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    @Autowired
    DataSource dataSource1;

    @Autowired
    DataSource dataSource2;

    /**
     * 此方法作用是返回当前数据源标识
     *
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return threadLocal.get();
    }

    /**
     * 重写父类方法之前,为父类基础属性进行赋值
     */
    @Override
    public void afterPropertiesSet() {
        // 为AbstractRoutingDataSource的主要参数进行赋值

        // targetDataSources初始化所有数据源
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("ds1", dataSource1);
        targetDataSources.put("ds2", dataSource2);
        super.setTargetDataSources(targetDataSources);

        // defaultTargetDataSource设置默认数据源
        super.setDefaultTargetDataSource(dataSource1);

        super.afterPropertiesSet();
    }
    // 清除threadLocal变量
}

使用aop方式自动切换数据源

package com.aop;

import com.config.dualdb.DynamicDatasource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
public class DynamicDatasourceAspect {

    @Pointcut("execution(public * com.mapper.test1.*.*(..))")
    public void pointCut1() {
    }


    @Pointcut("execution(public * com.mapper.test2.*.*(..))")
    public void pointCut2() {
    }

    @Before(value = "pointCut1()")
    public void before1(JoinPoint jp) {
        String name = "解析token获取用户对应的数据源";
        // 通过反射拿到请求的相关信息,进行解析,获取相应的标识
        // 根据具体业务对应的标识设置请求哪个数据源
        // 优化点, 根据切点, 动态切换配置
        DynamicDatasource.threadLocal.set("ds1");
        log.info(name);
    }

    @After("pointCut1()")
    public void after1(JoinPoint joinPoint) {
        DynamicDatasource.threadLocal.remove();
    }

    @Before(value = "pointCut2()")
    public void before2(JoinPoint jp) {
        String name = "解析token获取用户对应的数据源";
        // 通过反射拿到请求的相关信息,进行解析,获取相应的标识
        // 根据具体业务对应的标识设置请求哪个数据源
        DynamicDatasource.threadLocal.set("ds2");
        log.info(name);
    }

    @After("pointCut2()")
    public void after2(JoinPoint joinPoint) {
        DynamicDatasource.threadLocal.remove();
    }
}

简单编写aop自动切换,通过解析当前执行包名称,自动获取数据源标识符,然后设置当前数据源,注意需要修改mapper目录下的包为对应数据源名称

import com.config.dualdb.DynamicDatasource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
public class DynamicDatasourceAspect {

    @Pointcut("execution(public * com.mapper.*.*.*(..))")
    public void pointCut1() {
    }

    @Before(value = "pointCut1()")
    public void before1(JoinPoint jp) {
        String name = "解析token获取用户对应的数据源";
        // 通过反射拿到请求的相关信息,进行解析,获取相应的标识
        // 根据具体业务对应的标识设置请求哪个数据源
        final String[] split = jp.getSignature().getDeclaringTypeName().split("\\.");
        String flag = split[split.length - 2];
        DynamicDatasource.threadLocal.set(flag);
        log.info(name);
    }

    @After("pointCut1()")
    public void after1(JoinPoint joinPoint) {
        DynamicDatasource.threadLocal.remove();
    }
}

参考:
配置参考:
【spring配置多数据源】spring连接多个数据库,同一套项目配置多个数据库
声明事务参考:
mybatis(plus)多数据源

你可能感兴趣的:(Java,spring,数据库,java)