springboot动态数据源切换(多数据源配置)

动态数据源切换即多数据源切换,由于业务的需要或者历史的遗留等原因,一个项目中配置了多个数据库,用于查询不同类型的数据,因此我们就需要经常在各个库中切换数据源,接下来我们将进行具体的说明:

项目结构如下:

相关类说明:

DynamicDataSource:动态获取数据源的实现,继承AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)

DynamicDataSourceContextHolder:动态数据源上下文管理,相当于在容器中管理数据源实例

DynamicDattaSourceAspect:动态数据源通知

TargetDataSource:数据源注解,作用于类、接口或者方法上,用于指定数据源

DynamicDatasourceConfig:动态数据源配置,实例化所有配置数据源

 

具体类实现:

DynamicDataSource


public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

DynamicDataSourceContextHolder:

    /**
     * 存放当前线程使用的数据源类型信息
     */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /**
     * 存放数据源id,即数据源实例名称
     */
    public static List<String> dataSourceIds = new ArrayList<String>();

    /**
     * 设置数据源
     *
     * @param dataSourceType
     */
    public static void setDataSourceType(String dataSourceType) {
        logger.info("添加数据源实例到管理器中,dataSourceType{}", dataSourceType);
        contextHolder.set(dataSourceType);
    }

    /**
     * 获取数据源
     *
     * @return
     */
    public static String getDataSourceType() {
        logger.info("从数据源实例管理器中获取当前实例");
        return contextHolder.get();
    }

    /**
     * 清除数据源
     */
    public static void clearDataSourceType() {
        logger.info("清除当前数据源实例");
        contextHolder.remove();
    }

    /**
     * 判断当前数据源是否存在
     *
     * @param dataSourceId
     * @return
     */
    public static boolean isContainsDataSource(String dataSourceId) {
        logger.info("判断当前数据源是否存在,dataSourceId={}", dataSourceId);
        return dataSourceIds.contains(dataSourceId);
    }

DynamicDattaSourceAspect

package com.xiaofeng.datasource2.aspect;

import com.xiaofeng.datasource2.aspect.annotation.TargetDataSource;
import com.xiaofeng.datasource2.dynamic.DynamicDataSourceContextHolder;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: DynamicDattaSourceAspect
 * @package: com.xiaofeng.sys.dynamic
 * @description: 动态数据源通知
 * @date 2019/8/28 16:48
 */
@Aspect
@Order(-1)
@Component
public class DynamicDattaSourceAspect {

    private Logger logger = LoggerFactory.getLogger(DynamicDattaSourceAspect.class);

    /**
     * 改变数据源,判断使用注解中的数据源实例名称,根据实例名称从上下文管理器中获取数据源
     *
     * @param joinPoint
     * @param targetDataSource
     */
    @Before("@annotation(targetDataSource)")
    public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        logger.info("选择数据源---" + targetDataSource.value().getValue());
        DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value().getValue());
    }

    /**
     * 使用完后清理数据源
     *
     * @param joinPoint
     * @param targetDataSource
     */
    @After("@annotation(targetDataSource)")
    public void clearDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        logger.debug("清除数据源 " + targetDataSource.value().getValue() + " !");
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
}

TargetDataSource


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {

    DataSourceEnum value() default DataSourceEnum.MASTER;
}

 

DynamicDatasourceConfig

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

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

    /**
     * 动态数据源配置
     *
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("master") DataSource master, @Qualifier("slave") DataSource slave) {
        DynamicDataSource multipleDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.MASTER.getValue(), master);
        targetDataSources.put(DataSourceEnum.SLAVE.getValue(), slave);
        //添加数据源
        multipleDataSource.setTargetDataSources(targetDataSources);
        //设置默认数据源
        multipleDataSource.setDefaultTargetDataSource(master);
        return multipleDataSource;
    }

测试类如下:

实现效果如下:

至此我们的多数据源配置(主从数据源)已完成,此种方式已经过亲测验证!

可运行完整源码下载地址http://zyshare.cn/resource/detail/10

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值