MybatisPlus 多数据源配置

 		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency> 

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

		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

<!-- greenplum 数据库依赖,不使用 greenplum-jdbc,因为mybatisplus 分页不能识别该url -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.5.1</version>
        </dependency>

配置文件

spring:
  # 数据源配置
  datasource:
    druid:
      type: com.alibaba.druid.pool.DruidDataSource
      # 主库数据源
      master:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/acquisition?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: admin
        password: 123456
      greenplum:
        driverClassName: org.postgresql.Driver
        url: jdbc:postgresql://localhost:5432/scada
        username: admin
        password: 123456

1.定义数据源名称枚举类

/**
 * 数据源
 * 
 * @author cheny
 */
public enum DataSourceType{
    /**
     * 主库
     */
    MASTER,

    /**
     * 从库
     */
    SLAVE,

    /**
     * greenplum
     */
    GREENPLUM
}

2.创建动态数据源

/**
 * 动态数据源
 * 
 * @author cheny
 */
public class DynamicDataSource extends AbstractRoutingDataSource{
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
    {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey()
    {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

3.数据源切换处理类

/**
 * 数据源切换处理
 * 
 * @author cheny
 */
public class DynamicDataSourceContextHolder{
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源的变量
     */
    public static void setDataSourceType(String dsType){
        log.info("切换到{}数据源", dsType);
        CONTEXT_HOLDER.set(dsType);
    }

    /**
     * 获得数据源的变量
     */
    public static String getDataSourceType(){
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType(){
        CONTEXT_HOLDER.remove();
    }
}

4.动态数据源配置

/**
 * druid 配置多数据源
 * 
 * @author cheny
 */
@Configuration
public class DruidConfig{
    
    /**
     * 创建 DataSource Bean
     */
    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource masterDataSource(DruidProperties druidProperties){
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.slave")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    public DataSource slaveDataSource(DruidProperties druidProperties){
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.greenplum")
    public DataSource greenplumDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource, DataSource greenplumDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
        targetDataSources.put(DataSourceType.GREENPLUM.name(), greenplumDataSource);
        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

    /**
     * 设置数据源
     * 
     * @param targetDataSources 备选数据源集合
     * @param sourceName 数据源名称
     * @param beanName bean名称
     */
    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) {
        try
        {
            DataSource dataSource = SpringUtils.getBean(beanName);
            targetDataSources.put(sourceName, dataSource);
        }
        catch (Exception e)
        {
        }
    }
}

5.定义动态数据源注解

/**
 * 自定义多数据源切换注解
 * 
 * @author cheny
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource{
    /**
     * 切换数据源名称
     */
    public DataSourceType value() default DataSourceType.MASTER;
}

6.设置数据源 AOP 代理

/**
 * 多数据源处理
 * 
 * @author cheny
 */
@Aspect
@Order(1)
@Component
public class DataSourceAspect
{
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(com.yang.annotation.DataSource)"
            + "|| @within(com.yang.annotation.DataSource)")
    public void dsPointCut() {}

    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        DataSource dataSource = getDataSource(point);

        if (StringUtils.isNotNull(dataSource)){
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
        }

        try {
            return point.proceed();
        }
        finally{
            // 销毁数据源 在执行方法之后
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    /**
     * 获取需要切换的数据源
     */
    public DataSource getDataSource(ProceedingJoinPoint point){
        MethodSignature signature = (MethodSignature) point.getSignature();
        Class<? extends Object> targetClass = point.getTarget().getClass();
        DataSource targetDataSource = targetClass.getAnnotation(DataSource.class);
        if (StringUtils.isNotNull(targetDataSource)) {
            return targetDataSource;
        }
        else {
            Method method = signature.getMethod();
            DataSource dataSource = method.getAnnotation(DataSource.class);
            return dataSource;
        }
    }
}

7.修改启动文件

// 动态数据源配置,需要将自有的配置依赖(DynamicDataSourceConfig),将原有的依赖去除(DataSourceAutoConfiguration)
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DataAqConfigApplication {

    public static void main(String[] args) throws UnknownHostException {
        SpringApplication.run(DataAqConfigApplication.class, args);
    }
}

测试

@Service
public class ScadaDataServiceImpl extends ServiceImpl<ScadaDataMapper, ScadaData> implements ScadaDataService {

    @DataSource(DataSourceType.GREENPLUM)
    @Override
    public Page<ScadaDataVO> deviceLogPage(ScadaDataPageReqVO reqVO) {
        ScadaDataPageReqBO reqBO = new ScadaDataPageReqBO();
        reqBO.setDeviceCode(reqVO.getDeviceCode());
        reqBO.setPropertyCode(reqVO.getPropertyCode());
        if (Objects.nonNull(reqVO.getBeginDateTime())){
            reqBO.setBeginDateTime(reqVO.getBeginDateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        }
        if (Objects.nonNull(reqVO.getEndDateTime())){
            reqBO.setEndDateTime(reqVO.getEndDateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        }
        return baseMapper.scadaDataPage(new Page(reqVO.getPageNum(), reqVO.getPageSize()), reqBO);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_46058921/article/details/128446618