SpringBoot实现动态切换数据源

一:Mybatis通过自定义注解方式实现

1.添加阿里巴巴druid数据库连接池依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
 </dependency>

2.修改配置文件

我这里分别用的是阿里云与华为云

spring:
  datasource:
    druid:
      alibaba:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: userName
        password: password
        url: jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=utf8&createDatabaseIfNotExist=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowMultiQueries=true
      huawei:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: username
        password: password
        url: jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=utf8&createDatabaseIfNotExist=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowMultiQueries=true

3.继承AbstractRoutingDataSource类并实现determineCurrentLookupKey方法

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    // 线程隔离
    private static final ThreadLocal<String> dataSourceHolder = new InheritableThreadLocal<>();


    /**
     * 设置数据源
     */
    public static void setDataSource(String dataSource) {
        dataSourceHolder.set(dataSource);
    }

    /**
     * 清除数据源
     */
    public static void removeDataSource() {
        dataSourceHolder.remove();
    }

    /**
     * 获取当前数据源
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceHolder.get();
    }
}

4.创建自定义注解,通过此注解指定数据源


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 切换指定数据源注解
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomDataSource {

    String value() default "alibaba";
}

5.新建AOP切面,切上面新建的自定义注解

import com.xxx.xxx.annotation.CustomDataSource;
import com.xxx.xxx.config.DynamicDataSource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspect {

    @Around("@annotation(com.xxx.xxx.annotation.CustomDataSource) || @within(com.xxx.xxx.annotation.CustomDataSource)")
    public Object switchDataSource(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        CustomDataSource dataSource = signature.getMethod().getAnnotation(CustomDataSource.class);
        if (dataSource == null) {
            Class<?> declaringType = signature.getDeclaringType();
            dataSource = declaringType.getAnnotation(CustomDataSource.class);
        }
        if (dataSource == null) {
            // 这里我默认了使用阿里巴巴
            DynamicDataSource.setDataSource("alibaba");
        } else {
            DynamicDataSource.setDataSource(dataSource.value());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.removeDataSource();
        }
    }
}

6.新建多数据源配置类

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;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DataSourceConfig {

    /**
     * 配置多数据源
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.druid.alibaba")
    public DataSource alibabaDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.druid.huawei")
    public DataSource huaweiDataSource() {
        return DruidDataSourceBuilder.create().build();
    }


    /**
     * 配置动态数据源
     */
    @Bean
    public DynamicDataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("alibaba", alibabaDataSource());
        targetDataSources.put("huawei", huaweiDataSource());

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(alibabaDataSource());

        return dataSource;
    }
}

7.新建mybatis配置类

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;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DataSourceConfig {

    /**
     * 配置多数据源
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.druid.alibaba")
    public DataSource alibabaDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.druid.huawei")
    public DataSource huaweiDataSource() {
        return DruidDataSourceBuilder.create().build();
    }


    /**
     * 配置动态数据源
     */
    @Bean
    public DynamicDataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("alibaba", alibabaDataSource());
        targetDataSources.put("huawei", huaweiDataSource());

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(alibabaDataSource());

        return dataSource;
    }
}

8.需要指定数据源的方法上增加注解

@CustomDataSource("huawei")
@Override
public User getUserFromHuawei(Long id) {
    return userMapper.selectById(id);
}

二:mybatis-plus实现方式

1.添加多数据源maven依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.6.1</version>
</dependency>

2.修改配置文件

spring:
  datasource:
    dynamic:
      primary: alibaba # 默认数据源
      strict: false
      datasource:
        alibaba:
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: userName
          password: password
          url: jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=utf8&createDatabaseIfNotExist=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowMultiQueries=true
        huawei:
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: username
          password: password
          url: jdbc:mysql://host:port/database?useUnicode=true&characterEncoding=utf8&createDatabaseIfNotExist=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&allowMultiQueries=true

3.需要指定数据源的方法上增加注解

@DS("huawei")
@Override
public User getUserFromHuawei(Long id) {
    return userMapper.selectById(id);
}

三:测试

image.png

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容