Mysql的数据源大家用的应该很多,这里我们说一种简单的多数据源的实现方法(aop+springboot+注解实现),基于SpringBoot。
AbstractRoutingDataSource介绍
Spring boot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
所以我们只要实现集成这个类并重写determineCurrentLookupKey方法就可以实现多数据源的切换;
DataSourceBuilder
spring boot提供了DataSourceBuilder来进行构建DataSource,我们可以使用DataSourceBuilder来构建任意个数据源。
构建完毕数据源后利用上述我们集成的AbstractRoutingDataSource类的determineCurrentLookupKey方法便可以进行不同数据源切换。
现在我们进行一些基础代码的编写:
首先我们集成AbstractRoutingDataSource并重写determineCurrentLookupKey方法来进行切换
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
然后编写核心的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 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
我们建立一个类来进行存储当前的数据源是什么
public class DataSourceContextHolder {
private static final ThreadLocal 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();
}
}
此时我们已经可以进行数据源的切换了。
可以使用 DataSourceContextHolder.setDataSource(DataSourceType.MASTER); 来进行数据源的切换。
在此之上,为了更便捷的使用。我们可以用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);
}
}
使用方法
我们可以在dao层或者service层使用,在方法上加上注解就可以啦,如下
@Repository
public interface IntegralRepository {
@DataSource(value = DataSourceType.INTEGRAL)
void save(@Param("tableName") String tableName, @Param("integral") Integral integral);
}
在每次非master数据源切换完成后都会切换回master。
以上,便是简单的多数据源配置实现方法。