• 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); }
    
    
  • 相关阅读:
    【产品经理】原型设计工具
    Android进阶推荐书籍
    EventBus学习笔记(一)
    Android APT
    注解学习笔记(二)
    Android开发的小经验总结(上)
    Android开发的小经验总结(下)
    Windows环境下Android Studio v1.0安装教程
    Android-Universal-Image-Loader 图片异步加载类库的使用
    Android 官方推荐 : DialogFragment 创建对话框
  • 原文地址:https://www.cnblogs.com/chengzhihua/p/13202956.html
Copyright © 2020-2023  润新知