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。
以上,便是簡單的多數據源配置實現方法。
