天天看點

spring boot mybatis 多資料源

1.application.properties:

#default---開發環境 spring.datasource.default.driver-class-name=oracle.jdbc.OracleDriver spring.datasource.default.jdbc-url=jdbc:oracle:thin:@10.XX.27.XX:1521:orcl spring.datasource.default.username=aaa spring.datasource.default.password=aaa #datacenter---開發環境 spring.datasource.datacenter.driver-class-name=com.mysql.jdbc.Driver spring.datasource.datacenter.url=jdbc:mysql://10.XX.XX.XX:3403/db_cs?useUnicode=true&characterEncoding=UTF-8 spring.datasource.datacenter.username=bbb spring.datasource.datacenter.password=bbb

2.編寫資料源枚舉類DataSourceEnum:

public enum DataSourceEnum{
DEFAULT_DS("default"),
DATA_CENTER_DS("datacenter");

DataSourceEnum(String key) {
this.key = key;
}

private String key;

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}
}
           

3.編寫動态資料源類DynamicDataSource:

使用ThreadLocal,将不同線程隔離開,每個線程使用自己的資料源

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.Map;

public class DynamicDataSource extends AbstractRoutingDataSource {
public static final ThreadLocal<String> DATA_SOURCE = new ThreadLocal<>();

public DynamicDataSource(DataSource dataSource, Map<Object, Object> dataSourceMap){
// 預設使用的資料源
super.setDefaultTargetDataSource(dataSource);
super.setTargetDataSources(dataSourceMap);
super.afterPropertiesSet();
}

// 這個方法傳回的是目前線程使用的資料源key
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}


public static void setDataSource(String dataSource){
DATA_SOURCE.set(dataSource);
}

public static String getDataSource(){
return DATA_SOURCE.get();
}

public static void removeDataSource(){
DATA_SOURCE.remove();
}
}
           

4.編寫動态資料源配置類DynamicDataSourceConfig:

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DynamicDataSourceConfig {
@Bean("defaultDataSource")
@ConfigurationProperties("spring.datasource.default")// 對應application.properties中的配置
public DataSource defaultDataSource(){
return DataSourceBuilder.create().build();
}


@Bean("dataCenterDataSource")
@ConfigurationProperties("spring.datasource.datacenter")
public DataSource dataCenterDataSource(){
return DataSourceBuilder.create().build();
}



@Primary //預設資料源配置
@Bean
public DynamicDataSource dataSource(@Qualifier("defaultDataSource") DataSource defaultDataSource , @Qualifier("dataCenterDataSource") DataSource dataCenterDataSource){
Map<Object, Object> map = new HashMap<>();
map.put(DataSourceEnum.DEFAULT_DS.getKey(), defaultDataSource);
map.put(DataSourceEnum.DATA_CENTER_DS.getKey(), dataCenterDataSource);
return new DynamicDataSource(defaultDataSource, map);
}
}
           

5.編寫注解類DS:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)// 運作時使用
@Target({ElementType.METHOD}) // 方法級注解
public @interface DS {
DataSourceEnum name() default DataSourceEnum.DEFAULT_DS;
}
           

6.編寫切面類DataSourceAspect:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Aspect
@Component
@Order(-1)
public class DataSourceAspect {
@Around("@annotation(com.yunda.config.DS)")
public Object around(ProceedingJoinPoint point) throws Throwable{
MethodSignature signature = (MethodSignature)point.getSignature();
Method method = signature.getMethod();
DS ds = method.getAnnotation(DS.class);
if(ds == null){
DynamicDataSource.setDataSource(DataSourceEnum.DEFAULT_DS.getKey());
System.out.println(Thread.currentThread().getName() + ": dataSource is " + DataSourceEnum.DEFAULT_DS.getKey());
}else{
DynamicDataSource.setDataSource(ds.name().getKey());
System.out.println(Thread.currentThread().getName() + ": dataSource is " + ds.name().getKey());
}

try {
return point.proceed();
} finally {
DynamicDataSource.removeDataSource();
System.out.println(Thread.currentThread().getName() + ": remove dataSource");
}
}
}
           

7.開啟切面自動代理,關閉預設資料源配置:

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableFeignClients
@EnableAspectJAutoProxy
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BootApplication {

public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}