1:首先yml配置两个数据库的链接
spring:application:name: xxxxmain:banner-mode: 'OFF'datasource: # 默认数据源 datamarkdruid: # 关闭数据库的 web 访问stat-view-servlet:enabled: falseweb-stat-filter:enabled: falsefilter:stat:enabled: falsetype: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: ${spring.twodb.driver-class-name}url: ${spring.infodata.url}username: ${spring.xxx.username}password: ${spring.xxx.password}max-active: 100min-idle: 10initial-size: 10max-wait: 10000connection-error-retry-attempts: 5 # 设置重连次数break-after-acquire-failure: true # 连接错误后退出time-between-connect-error-millis: 1000 # 重连间隔twodb:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:@10.1.1.1:1528/secusername: xxpassword: xxmax-active: 100min-idle: 10initial-size: 10max-wait: 10000connection-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@Primarypublic 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 {@Overrideprotected 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;}@Overridepublic 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);}
}
以上是自定义动态数据源+事务控制 关注老哥带你上高速 。。。。。。。。。