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。 

以上,便是简单的多数据源配置实现方法。
posted @ 2020-04-30 17:18  faylinn  阅读(969)  评论(0编辑  收藏  举报
、、、