動態數據源切換即多數據源切換,由於業務的需要或者歷史的遺留等原因,一個項目中配置了多個數據庫,用於查詢不同類型的數據,因此我們就需要經常在各個庫中切換數據源,接下來我們將進行具體的說明:
項目結構如下:
相關類說明:
DynamicDataSource:動態獲取數據源的實現,繼承AbstractRoutingDataSource(每執行一次數據庫,動態獲取DataSource)
DynamicDataSourceContextHolder:動態數據源上下文管理,相當於在容器中管理數據源實例
DynamicDattaSourceAspect:動態數據源通知
TargetDataSource:數據源註解,作用於類、接口或者方法上,用於指定數據源
DynamicDatasourceConfig:動態數據源配置,實例化所有配置數據源
具體類實現:
DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceType();
}
}
DynamicDataSourceContextHolder:
/**
* 存放當前線程使用的數據源類型信息
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
/**
* 存放數據源id,即數據源實例名稱
*/
public static List<String> dataSourceIds = new ArrayList<String>();
/**
* 設置數據源
*
* @param dataSourceType
*/
public static void setDataSourceType(String dataSourceType) {
logger.info("添加數據源實例到管理器中,dataSourceType{}", dataSourceType);
contextHolder.set(dataSourceType);
}
/**
* 獲取數據源
*
* @return
*/
public static String getDataSourceType() {
logger.info("從數據源實例管理器中獲取當前實例");
return contextHolder.get();
}
/**
* 清除數據源
*/
public static void clearDataSourceType() {
logger.info("清除當前數據源實例");
contextHolder.remove();
}
/**
* 判斷當前數據源是否存在
*
* @param dataSourceId
* @return
*/
public static boolean isContainsDataSource(String dataSourceId) {
logger.info("判斷當前數據源是否存在,dataSourceId={}", dataSourceId);
return dataSourceIds.contains(dataSourceId);
}
DynamicDattaSourceAspect
package com.xiaofeng.datasource2.aspect;
import com.xiaofeng.datasource2.aspect.annotation.TargetDataSource;
import com.xiaofeng.datasource2.dynamic.DynamicDataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author xiaofeng
* @version V1.0
* @title: DynamicDattaSourceAspect
* @package: com.xiaofeng.sys.dynamic
* @description: 動態數據源通知
* @date 2019/8/28 16:48
*/
@Aspect
@Order(-1)
@Component
public class DynamicDattaSourceAspect {
private Logger logger = LoggerFactory.getLogger(DynamicDattaSourceAspect.class);
/**
* 改變數據源,判斷使用註解中的數據源實例名稱,根據實例名稱從上下文管理器中獲取數據源
*
* @param joinPoint
* @param targetDataSource
*/
@Before("@annotation(targetDataSource)")
public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
logger.info("選擇數據源---" + targetDataSource.value().getValue());
DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value().getValue());
}
/**
* 使用完後清理數據源
*
* @param joinPoint
* @param targetDataSource
*/
@After("@annotation(targetDataSource)")
public void clearDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
logger.debug("清除數據源 " + targetDataSource.value().getValue() + " !");
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
TargetDataSource
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
DataSourceEnum value() default DataSourceEnum.MASTER;
}
DynamicDatasourceConfig
@Bean(name = "master")
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource master() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slave")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave")
public DataSource slave() {
return DruidDataSourceBuilder.create().build();
}
/**
* 動態數據源配置
*
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("master") DataSource master, @Qualifier("slave") DataSource slave) {
DynamicDataSource multipleDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.MASTER.getValue(), master);
targetDataSources.put(DataSourceEnum.SLAVE.getValue(), slave);
//添加數據源
multipleDataSource.setTargetDataSources(targetDataSources);
//設置默認數據源
multipleDataSource.setDefaultTargetDataSource(master);
return multipleDataSource;
}
測試類如下:
實現效果如下:
至此我們的多數據源配置(主從數據源)已完成,此種方式已經過親測驗證!
可運行完整源碼下載地址:http://zyshare.cn/resource/detail/10