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); }

 

posted @ 2020-06-28 15:17  喜中5000万  阅读(4943)  评论(2编辑  收藏  举报