springboot的mysql多數據源實現


Mysql的數據源大家用的應該很多,這里我們說一種簡單的多數據源的實現方法(aop+springboot+注解實現),基於SpringBoot。

AbstractRoutingDataSource介紹
  • Spring boot提供了AbstractRoutingDataSource 根據用戶定義的規則選擇當前的數據源,這樣我們可以在執行查詢之前,設置使用的數據源。實現可動態路由的數據源,在每次數據庫查詢操作前執行。它的抽象方法 determineCurrentLookupKey() 決定使用哪個數據源。

所以我們只要實現集成這個類並重寫determineCurrentLookupKey方法就可以實現多數據源的切換;

DataSourceBuilder
  • spring boot提供了DataSourceBuilder來進行構建DataSource,我們可以使用DataSourceBuilder來構建任意個數據源。
  • 構建完畢數據源后利用上述我們集成的AbstractRoutingDataSource類的determineCurrentLookupKey方法便可以進行不同數據源切換。

現在我們進行一些基礎代碼的編寫:

  1. 首先我們集成AbstractRoutingDataSource並重寫determineCurrentLookupKey方法來進行切換
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

  1. 然后編寫核心的DataSourceConfig
@Configuration
public class MybatisConfig {
    @Bean("masterDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().type(com.alibaba.druid.pool.DruidDataSource.class).build();
    }

    @Bean("integralDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.integral")
    public DataSource integralDataSource() {
        return DataSourceBuilder.create().type(com.alibaba.druid.pool.DruidDataSource.class).build();
    }

    /**
     * 將兩種數據源放到spring管理
     */
    @Bean
    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                        @Qualifier("integralDataSource") DataSource integralDataSource) {

        Map<Object, Object> map = new HashMap<>();
        map.put(DataSourceType.MASTER, masterDataSource);
        map.put(DataSourceType.INTEGRAL, integralDataSource);

        // 將兩個數據源放到map里並set到DynamicDataSource對象里
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(map);
        // 設置默認數據源為master
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);

        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dynamicDataSource);
//        factoryBean.setTypeAliasesPackage();
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml");
        factoryBean.setMapperLocations(resources);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setCallSettersOnNulls(true);
        factoryBean.setConfiguration(configuration);
        return factoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }
}
public enum DataSourceType {
    MASTER,
    INTEGRAL,
    ;
}

DataSourceConfig類實現創建了兩個DataSource,分別為master和integral兩個。然后我們將這兩個Bean交給了DynamicDataSource 管理,並制定了默認數據源為master

  1. 我們建立一個類來進行存儲當前的數據源是什么
public class DataSourceContextHolder {

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

    public static void setDataSource(DataSourceType type) {
        contextHolder.set(type);
    }

    public static DataSourceType getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }
}
  1. 此時我們已經可以進行數據源的切換了。
    可以使用 DataSourceContextHolder.setDataSource(DataSourceType.MASTER); 來進行數據源的切換。

  2. 在此之上,為了更便捷的使用。我們可以用aop+注解的形式解放雙手,使得代碼簡約一些,不用可以切換數據源。

    • 我們先建立一個注解
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
    		DataSourceType value() default DataSourceType.MASTER;
    }
    
    • 然后建立個Aspect來進行數據源的切換
    @Slf4j
    @Aspect
    @Component
    public class DataSourceAspect {
    	@Before("@annotation(ds)")
    	public void beforeDataSource(DataSource ds) {
        	DataSourceType value = ds.value();
        	DataSourceContextHolder.setDataSource(value);
    	}
    
    	@After("@annotation(ds)")
    	public void afterDataSource(DataSource ds) {
        	DataSourceContextHolder.setDataSource(DataSourceType.MASTER);
    	}
    }
    
  3. 使用方法
    我們可以在dao層或者service層使用,在方法上加上注解就可以啦,如下

    @Repository
    public interface IntegralRepository {
    
    	@DataSource(value = DataSourceType.INTEGRAL)
    	void save(@Param("tableName") String tableName, @Param("integral") Integral integral);
    }
    
    
在每次非master數據源切換完成后都會切換回master。 

以上,便是簡單的多數據源配置實現方法。


免責聲明!

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



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