springboot繼承AbstractRoutingDataSource可以實現數據源。
1.先寫繼承AbstractRoutingDataSource的類
(1).DynamicDataSource 是設置默認數據源和已經存在的所有數據源
(2).這個determineCurrentLookupKey是從當前線程獲取設置的數據源
public class DynamicDataSource extends AbstractRoutingDataSource
{
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
{
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey()
{
return DynamicDataSourceContextHolder.getDateSoureType();
}
}
2.DynamicDataSourceContextHolder設置當前線程處理數據源的類
public class DynamicDataSourceContextHolder {
public static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
private static final ThreadLocal<String> DATASOURCE_CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 設置數據源
*/
public static void setDateSoureType(String dateSoureType) {
logger.info("設置數據源={}", dateSoureType);
DATASOURCE_CONTEXT_HOLDER.set(dateSoureType);
}
/**
* 獲得數據源
*/
public static String getDateSoureType() {
return DATASOURCE_CONTEXT_HOLDER.get();
}
/**
* 清空數據源
*/
public static void clearDateSoureType() {
DATASOURCE_CONTEXT_HOLDER.remove();
}
}
3.配置Hikari數據源和包位置
@Configuration
@MapperScan("com.fast.framework.dao")
public class HikariCustomConfig {
public static final Logger logger = LoggerFactory.getLogger(HikariCustomConfig.class);
@Value("${mybatis.config-location}")
private String configLocation;
@Value("${mybatis.type-aliases-package}")
private String typeAliasespackage;
@Bean("master")
@ConfigurationProperties(prefix = "spring.datasource.hikari.master")
public HikariDataSource masterDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean("second")
@ConfigurationProperties(prefix = "spring.datasource.hikari.second")
public HikariDataSource slaveDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("master") DataSource masterDataSource, @Qualifier("second") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(AllDatasource.MASTER.name(), masterDataSource);
targetDataSources.put(AllDatasource.SECOND.name(), slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
/**
* @description: 配置mybatis的mapper和dao的位置
*/
@Bean("sqlSessionFactoryBean")
public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(configLocation));
sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasespackage);
return sqlSessionFactoryBean;
}
/**
* 事務管理
*/
@Bean
public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
4.設置aop註解,通過註解設置數據源
@Aspect
@Order(1)
@Component
public class DataSourceAop {
@Value("${spring.datasource.hikari.master.default-package}")
private String masterPackage;
@Value("${spring.datasource.hikari.second.default-package}")
private String secondPackage;
public static final Logger logger = LoggerFactory.getLogger(DataSourceAop.class);
@Pointcut("execution(* com.fast.framework.dao..*.*(..)) ||@annotation(com.fast.common.annotation.ChooseDataSource)")
public void switchDataSource() {
}
@Before("switchDataSource()")
public void doBefore(JoinPoint joinPoint) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
ChooseDataSource chooseDataSource = method.getAnnotation(ChooseDataSource.class);//獲取方法上的註解
if (chooseDataSource == null) {
chooseDataSource = joinPoint.getTarget().getClass().getAnnotation(ChooseDataSource.class);//獲取類上面的註解
if (chooseDataSource == null) {
String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
if (declaringTypeName.startsWith(masterPackage)) {
DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.MASTER.name());
logger.info("使用包默認數據源,包={},數據源={}", masterPackage, AllDatasource.MASTER.name());
} else if (declaringTypeName.startsWith(secondPackage)) {
DynamicDataSourceContextHolder.setDateSoureType(AllDatasource.SECOND.name());
logger.info("使用包默認數據源,包={},數據源={}", secondPackage, AllDatasource.SECOND.name());
}
return;
} else {
logger.info("類註解生效,切換數據源={}", chooseDataSource.dataSource().name());
}
} else {
logger.info("方法註解生效,切換數據源={}", chooseDataSource.dataSource().name());
}
//獲取註解上的數據源的值的信息
String dataSourceName = chooseDataSource.dataSource().name();
if (dataSourceName != null) {
//給當前的執行SQL的操作設置特殊的數據源的信息
DynamicDataSourceContextHolder.setDateSoureType(dataSourceName);
}
String nowDatasource = "".equals(dataSourceName) ? "默認數據源master" : dataSourceName;
logger.info("AOP註解切換數據源,className" + joinPoint.getTarget().getClass().getName() + "methodName" + method.getName() + ";dataSourceName:" + nowDatasource);
}
@After("switchDataSource()")
public void after(JoinPoint point) {
//清理掉當前設置的數據源,讓默認的數據源不受影響
DynamicDataSourceContextHolder.clearDateSoureType();
}
}
5.配置數據源和包位置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
maximum-pool-size: 20
max-lifetime: 30000
idle-timeout: 30000
master:
default-package: com.fast.framework.dao.master
jdbc-url: jdbc:mysql://localhost:3306/fastblack?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
username: root
password: 123456
second:
default-package: com.fast.framework.dao.second
jdbc-url: jdbc:mysql://localhost:3306/base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=true
username: root
password: 123456
mybatis:
config-location: classpath*:/mapper/*/*.xml
type-aliases-package: com.fast.framework.model
6.枚舉和切換數據源註解
public enum AllDatasource {
MASTER,
SECOND;
}
註解:
/**
* @Auther: Administrator
* @Date: 2019/6/9 16:36
* @Description:設置數據源 優先級:1.方法註解 2.類註解 3.根據包路徑設置的數據源
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChooseDataSource {
AllDatasource dataSource() default AllDatasource.MASTER;
}
最後,這個是經過測試可以使用的,各位需要有基礎,配置的時候直接拷貝修改一下就好了。