zoukankan      html  css  js  c++  java
  • 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); }
    
    
  • 相关阅读:
    x01.os.17: 换心术
    x01.os.16: 添加功能
    x01.os.15: 看上去很美
    JVM 栈帧之操作数栈与局部变量表
    IDEA字节码学习查看神器jclasslib bytecode viewer介绍
    java上下文Context类
    UML ——区分类图中的几种关系.md
    UML ——六种依赖关系.md
    JDK动态代理[1]----代理模式实现方式的概要介绍
    java方法句柄-----5.Method Handles in Java
  • 原文地址:https://www.cnblogs.com/chengzhihua/p/13202956.html
Copyright © 2011-2022 走看看