springboot之动态切换多数据源

背景:最近有一个需求是根据app传来的请求参数,根据行政部门编码请求不同地区的数据,之前写的多数据源都是固定某个方法调用指定的dao然后查询不同的数据库,但是这次是需要根据前端传入参数进行动态区分数据库,所以就需要做特殊处理

 

1.注册多数据源:

@Configuration
public class DataSourceConfiguration {

    /**
     *  交管局数据源
     */
    @Bean(name = "jiaoguanjuDataSource")
    @Qualifier("jiaoguanjuDataSource")
    @ConfigurationProperties(prefix="spring.datasource.jiaoguanju")
    public DataSource jiaoguanjuDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     *  广州数据源
      */
    @Bean(name = "guangzhouDataSource")
    @Qualifier("guangzhouDataSource")
    @ConfigurationProperties(prefix="spring.datasource.guangzhou")
    public DataSource guangzhouDataSource() {
        return DataSourceBuilder.create().build();
    }
    /**
     *  清远数据源
     */
    @Bean(name = "qingyuanDataSource")
    @Qualifier("qingyuanDataSource")
    @ConfigurationProperties(prefix="spring.datasource.qingyuan")
    public DataSource qingyuanDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     *  韶关数据源
     */
    @Bean(name = "shaoguanDataSource")
    @Qualifier("shaoguanDataSource")
    @ConfigurationProperties(prefix="spring.datasource.shaoguan")
    public DataSource shaoguanDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * cancl数据源
      */
    @Bean(name = "secondaryDataSource")
    @Qualifier("secondaryDataSource")
    @ConfigurationProperties(prefix="spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "dynamicDataSource")
    @Primary
    public DataSource dynamicDataSource(){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.myMap = new HashMap<>();//保存我们有的数据源,方便后面动态增加
        dynamicDataSource.myMap.put("guangzhou",guangzhouDataSource());
        dynamicDataSource.myMap.put("qingyuan",qingyuanDataSource());
        dynamicDataSource.myMap.put("shaoguan",shaoguanDataSource());
        dynamicDataSource.myMap.put("jiaoguanju", jiaoguanjuDataSource());
//        dynamicDataSource.myMap.put("3",thirdDataSource());
        dynamicDataSource.setTargetDataSources(dynamicDataSource.myMap);//父类的方法
        DynamicDataSourceContextHolder.dataSourceIds.addAll(dynamicDataSource.myMap.keySet());
        dynamicDataSource.setDefaultTargetDataSource(guangzhouDataSource());//父类的方法
        return  dynamicDataSource;
    }


}

 

2.将数据源交给AbstractRoutingDataSource

/**
 * @Author Cheng ZhiHua
 * @Date 2019-11-05 16:01
 * @Description 核心方法 :继承AbstractRoutingDataSource 类,将数据源交给AbstractRoutingDataSource进行注入使用
 **/
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    public Map<Object,Object> myMap = null;

    @Override
    protected Object determineCurrentLookupKey() {
        /*
         * DynamicDataSourceContextHolder代码中使用setDataSourceType
         * 设置当前的数据源,在路由类中使用getDataSourceType进行获取,
         *  交给AbstractRoutingDataSource进行注入使用。
         */
//        log.info("数据源为: {}",DynamicDataSourceContextHolder.getDataSourceType());
        return DynamicDataSourceContextHolder.getDataSourceType();

    }

}

 

3.每个请求与线程绑定,保证各个请求之前互不影响

/**
 * @Author Cheng ZhiHua
 * @Date 2019-11-05 16:02
 * @Description
 **/
public class DynamicDataSourceContextHolder {
    /*

     * 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,

     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

     */

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();


    public static List<Object> dataSourceIds = new ArrayList<Object>();


    public static void setDataSourceType(String dataSourceType) {

        contextHolder.set(dataSourceType);

    }


    public static String getDataSourceType() {

        return contextHolder.get();

    }


    public static void clearDataSourceType() {

        contextHolder.remove();

    }


    public static boolean containsDataSource(String dataSourceId) {

        return dataSourceIds.contains(dataSourceId);

    }

}

 4.调用一定要在事务之前,在controller层

/**
 * 设置当前线程的数据库连接
 *
 * @param data
 */
private void ThreadLocalParamSet(Map<String, Object> data) {
        Map<String, String> userInfo = (Map<String, String>) data.get("userInfo");
        String dataSourceType =
                deptnoReleaseDatasourceMap.get(userInfo.get("userDeptNo").substring(0, 4));
        DynamicDataSourceContextHolder.setDataSourceType(dataSourceType);
}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值