1:首先yml配置两个数据库的链接
spring:
application:
name: xxxx
main:
banner-mode: 'OFF'
datasource: # 默认数据源 datamark
druid: # 关闭数据库的 web 访问
stat-view-servlet:
enabled: false
web-stat-filter:
enabled: false
filter:
stat:
enabled: false
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: ${spring.twodb.driver-class-name}
url: ${spring.infodata.url}
username: ${spring.xxx.username}
password: ${spring.xxx.password}
max-active: 100
min-idle: 10
initial-size: 10
max-wait: 10000
connection-error-retry-attempts: 5 # 设置重连次数
break-after-acquire-failure: true # 连接错误后退出
time-between-connect-error-millis: 1000 # 重连间隔
twodb:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@10.1.1.1:1528/sec
username: xx
password: xx
max-active: 100
min-idle: 10
initial-size: 10
max-wait: 10000
connection-error-retry-attempts: 5 # 设置重连次数
break-after-acquire-failure: true # 连接错误后退出
time-between-connect-error-millis: 1000 # 重连间隔
2:定义枚举
@AllArgsConstructor
@Getter
public enum DataSourceEnum {
DEFAULT("default"), TWODB("twodb");
private final String value;
}
2.1:方便后续需要用到数据源直接使用注解的形式进行切换即可
定义DataSource注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
DataSourceEnum source() default DataSourceEnum.DEFAULT;
}
3:项目启动配置数据库的链接信息
@Configuration
public class DataSourceConfig {
@Bean(name = "default")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource defaultDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "twodb")
@ConfigurationProperties(prefix = "spring.infodata")
public DataSource infoDataSource() {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("default") DataSource defaultDataSource,
@Autowired(required = false) @Qualifier("infodata") DataSource infodata) {
MultipleDataSource multipleDataSource = new MultipleDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.DEFAULT.getValue(), defaultDataSource);
if (defaultDataSource != null) {
targetDataSources.put(DataSourceEnum.INFODATA.getValue(), infodata);
}
//添加数据源
multipleDataSource.setTargetDataSources(targetDataSources);
//设置默认数据源
multipleDataSource.setDefaultTargetDataSource(defaultDataSource);
return multipleDataSource;
}
}
4:管理动态数据源
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
5:动态数据源上下文处理
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();
/**
* 设置数据源
*
* @param db
*/
public static void setDataSource(String db) {
contextHolder.set(db);
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDataSource() {
return contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clear() {
contextHolder.remove();
}
}
6:使用aop动态代理实现数据源的切换
@Slf4j
@Aspect
@Component
public class DataSourceAspect implements Ordered {
public static final String DEFAULT_SOURCE = DataSourceEnum.DEFAULT.getValue();
public DataSourceAspect() {
}
@Pointcut("@within(DataSource注解所在额包路径) || @annotation(DataSource注解所在额包路径))")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) {
String source = DataSourceContextHolder.getDataSource();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> aClass = point.getTarget().getClass();
DataSource annotation = aClass.getAnnotation(DataSource.class);
DataSource dataSource = method.getAnnotation(DataSource.class);
if (needSwitchDataSource(point)) {
if (annotation != null) {
DataSourceContextHolder.setDataSource(annotation.source().getValue());
log.debug("set datasource is " + annotation.source().getValue());
} else {
DataSourceContextHolder.setDataSource(dataSource.source().getValue());
log.debug("set datasource is " + dataSource.source().getValue());
}
}
Object var5;
try {
var5 = point.proceed();
} catch (Throwable e) {
throw new CustomException(e.getMessage(), e);
} finally {
if (needSwitchDataSource(point)) {
DataSourceContextHolder.setDataSource(source);
log.debug("clean datasource");
}
}
return var5;
}
private boolean needSwitchDataSource(ProceedingJoinPoint point) {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> aClass = point.getTarget().getClass();
DataSource annotation = aClass.getAnnotation(DataSource.class);
DataSource dataSource = method.getAnnotation(DataSource.class);
return annotation != null || dataSource != null;
}
@Override
public int getOrder() {
return 1;
}
}
7:在切换数据源直接查询时候需要将事务进行重新创建一个新事物处理事务的情况 如下使用
在业务类型上添加如下的代码实现切换
@Slf4j
@Service
@DataSource(source = DataSourceEnum.TWODB)
public class xxx{
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public List<SecuryInfo> getSecuryInfoBySecuID(List<String> secuIdList) {
return poolVarSecuInfoDao.selectSecuInfoByCond(null,null,secuIdList);
}
}
以上是自定义动态数据源+事务控制 关注老哥带你上高速 。。。。。。。。。