SpringBoot 多数据源配置

什么意思呢?就是一个项目配置多个数据库,比如在一个方法里,操作两个不同的数据库中的表!

我们的核心思想是:使用AOP+注解的方法来实现;

1、pom文件

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

2、启动类配置

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})//排除自动注入数据源
@EnableAspectJAutoProxy(exposeProxy = true) //aop代理
@MapperScan(basePackages = "com.casicloud.mapper")

3、application.yml 配置

spring:
  datasource:
    cloud:
      url: jdbc:mysql://xxxx:3306/cloud?useUnicode=true
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
    test:
      url: jdbc:mysql://xxxx:3306/test?useUnicode=true
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4、需要定义一个enum类:

/**
 * 数据源枚举类
 */
public enum DBTypeEnum {

    CLOUD_DB("cloud"),

    TEST_DB("test")
    ;

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }


    private DBTypeEnum(String value) {
        this.value = value;
    }
}

5、一个注解类

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DB {
    DBTypeEnum value() default DBTypeEnum.CLOUD_DB;
}

6、动态数据源切换类: AbstractRoutingDataSource
AbstractRoutingDataSource 类中 TargetDataSources(Map) 存放 key-datasource
重写的方法是获取key的方法

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {

        return DbContextHolder.getDbKey();
    }
}

7、使用ThreadLocal存放数据源的key

public class DbContextHolder {
    private static final ThreadLocal dbKey=new ThreadLocal<>();

    public static void setDbKey(DBTypeEnum dbTypeEnum){
        dbKey.set(dbTypeEnum.getValue());
    }

    public static String getDbKey(){
        return  (String)dbKey.get();
    }

    public static void cleanDbKey(){
        dbKey.remove();
    }
}

8、Druid数据源,这是真正的数据源

@Configuration
public class DruidConfig {

	//cloud 数据源
    @ConfigurationProperties(prefix = "spring.datasource.cloud")
    @Bean("cloud")
    public DataSource getCloudDateSource(){
        return new DruidDataSource();
    }
	//test数据源
    @ConfigurationProperties(prefix = "spring.datasource.test")
    @Bean("test")
    public DataSource getTestDateSource(){
        return new DruidDataSource();
    }
	//往动态数据源切换类中set key-datasource
    @Bean
    @Primary
    public DataSource multipartDataSource(@Qualifier("cloud") DataSource cloudDataSource,@Qualifier("test") DataSource testDataSource){
        DynamicDataSource dynamicDataSource=new DynamicDataSource();
        Map<Object,Object> targetDataSource=new HashMap<>();
        targetDataSource.put(DBTypeEnum.CLOUD_DB.getValue(),cloudDataSource);
        targetDataSource.put(DBTypeEnum.TEST_DB.getValue(),testDataSource);
        dynamicDataSource.setTargetDataSources(targetDataSource);
        return dynamicDataSource;
    }
    // 往sqlSessionFactory中set数据源 
    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(multipartDataSource(getCloudDateSource(),getTestDateSource()));
		//这里可以配置你的mapper.xml 的路径
//        PathMatchingResourcePatternResolver patternResolver = new  PathMatchingResourcePatternResolver();
//        sqlSessionFactoryBean.setMapperLocations(patternResolver.getResources("classpath:com/casicloud/mapper/*Mapper.xml"));

        return sqlSessionFactoryBean.getObject();
    }

}

9、AOP 代理

@Component
@Aspect
@Order(-100)
public class DataSourceSwitchAspect {

    @Pointcut("execution(* com.casicloud.service.impl..*.*(..))")
    private void dbAspect() {
    }

    @Before("dbAspect()")
    public void ChangeDataSource(JoinPoint joinPoint){
        Class<?> className = joinPoint.getTarget().getClass();
        //获得访问的方法名
        String methodName = joinPoint.getSignature().getName();
        //得到方法的参数的类型
        Class[] argClass = ((MethodSignature)joinPoint.getSignature()).getParameterTypes();
        try {
            Method method = className.getMethod(methodName, argClass);
            //注解在class上
            if(className.isAnnotationPresent(DB.class)){
                DB annotation = className.getAnnotation(DB.class);
                DbContextHolder.setDbKey(annotation.value());
            }
            //注解在method上
            if(method.isAnnotationPresent(DB.class)){
                DB annotation = method.getAnnotation(DB.class);
                DbContextHolder.setDbKey(annotation.value());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

10、到此,就可以实现了
通过在切入点上加注解,来实现动态的数据切换

 	@Override
    @DB(DBTypeEnum.CLOUD_DB)
    public void addUser(User user) {
        userMapper.addUser(user);
    }

	@Override
    @DB(DBTypeEnum.TEST_DB)
    public void addStudent(Student student) {
        studentMapper.addStudent(student);
    }

两个数据库,而我在controller中可以这样操作!

    @RequestMapping(value = "/addUserAndStudent",method = RequestMethod.GET)
    public void addUserAndStudent(){
        userService.addStudent(new Student(idWorker.nextId(),"和凯凯","男",19));
        userService.addUser(new User(idWorker.nextId(),"和凯凯","123456",LocalDateTime.now()));
    }

最后附上Githup链接:https://github.com/1277782574/SpringBootDynamicDataSource

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值