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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM