springboot mybatis plus多数据源轻松搞定(下)

springboot mybatis plus多数据源轻松搞定 (上) 中我们使用了分包的方式实现了一个springboot项目中多个数据源的调用。也对指出了最大的缺点就是不能灵活自由的切换数据源。那么这一篇中,我们探讨一下动态的实现多数据源的方式。可以实现随心所欲的切换数据源。

基础的配置

  1. 数据源的yml配置和上一结一样,就不在赘述了。
  2. 建立一个枚举类来标识两个数据源
public enum DataSourceType {
    emanage,ehr
}

建立一个线程和数据源之间的关联类

public class DataBaseContextHolder {
    private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
    public static void setDataSourceType(DataSourceType type)
    {
        if(type == null)
        {
            throw new NullPointerException();
        }

        contextHolder.set(type);
    }
    public static DataSourceType getDataSourceType()
    {
        DataSourceType type = contextHolder.get();
        if(type == null)
        {
            //确定一个默认数据源
            return DataSourceType.emanage;
        }
        return type;
    }
    
    public static void clearDataSrouceType()
    {
        contextHolder.remove();
    }
}

代码比较简单。就是当我们设置一个Mapper是通过那个数据源去访问数据的时候,把设置的参数保存在contextHolder中,为了处理线程安全,采用ThreadLocal的方式。

定义动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
 
    @Override
    protected Object determineCurrentLookupKey() {
 
        return DataBaseContextHolder.getDataSourceType();
    }
}

定义多数据源

@Configuration
@MapperScan("com.emanage.ehr.mapper")
public class DataSourceConfig {

    @Autowired
    private Environment env;

    @Bean(name = "datasource1")
    @ConfigurationProperties(prefix = "spring.datasource.emanage")
    public DruidDataSource druidDataSource1()
    {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.ehr")
    public DruidDataSource druidDataSource2()
    {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public DynamicDataSource dynamicDataSource(@Qualifier("datasource1") DruidDataSource ds1,
                                               @Qualifier("datasource2")  DruidDataSource ds2)
    {
        Map<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put(DataSourceType.emanage, ds1);
        targetDataSource.put(DataSourceType.ehr, ds2);
        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSource);
        dataSource.setDefaultTargetDataSource(ds1);
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {

        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        // 指定数据源
        bean.setDataSource(dynamicDataSource);
        bean.setMapperLocations(resolver.getResources("classpath*:mapper/**Mapper.xml"));

        return bean.getObject();
    }
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {

        return new DataSourceTransactionManager(dynamicDataSource);
    }

}

使用数据源

在调用mapper之前,在service中执行以下代码,可以灵活的切换数据源。

DataBaseContextHolder.setDataSourceType(DataSourceType.emanage); 
DataBaseContextHolder.setDataSourceType(DataSourceType.ehr); 

优化升级

感觉在sevrice中调用这些代码太过繁琐,可以自己定义两个注解。

public @interface DataSourceEmanage{}
public @interface DataSourceEHr{}

然后建立一个aop类让在有些注解的mapper类执行之前,先执行相应的数据源切换。

@Aspect
@Component
public class DataSourceAop {
    @Before("@annotation(com.example.demo3.config.DataSourceEmanage)")
    public void setEmanageDataSource()
    {
        DataBaseContextHolder.setDataSourceType(DataSourceType.emanage);
    }

    @Before("@annotation(com.example.demo3.config.DataSourceEhr)")
    public void setEhrDataSource()
    {
        DataBaseContextHolder.setDataSourceType(DataSourceType.ehr);
    }
}

只需要在mapper对应的方法上面设置注解,就可以很灵活的实现不同的方法调用不同的数据源。

posted @ 2020-06-19 18:35  bbird2018  阅读(769)  评论(0编辑  收藏  举报