springboot的mysql多数据源实现
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<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
- 我们建立一个类来进行存储当前的数据源是什么
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();
}
}
-
此时我们已经可以进行数据源的切换了。
可以使用 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。
以上,便是简单的多数据源配置实现方法。
时在中春,阳和方起