springboot运行时指定数据源切换 动态多数据源切换,mysql与h2数据库
springboot运行时指定数据源切换 动态多数据源切换
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、背景
需要在运行的时候从前端接受数据库参数来切换数据源,类似自己实现一个配置中心
二、使用步骤
1.引入maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
```<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<version>1.4.199</version><!--低版本,支持访问内存数据库-->
</dependency>
## 2.读入数据
核心代码如下(示例):
```xml
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.druid")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
@DependsOn({"springUtils", "defaultDataSource"})
public DynamicDataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(DynamicDataSource.dataSourcesMap);
return dynamicDataSource;
}
```public class DynamicDataSource extends AbstractRoutingDataSource {
private static String dataSourceKey = "defaultDataSource";
public static Map<Object, Object> dataSourcesMap = new ConcurrentHashMap<>(10);
static {
dataSourcesMap.put("defaultDataSource", SpringUtils.getBean("getDefaultDataSource"));
//dataSourcesMap.put("defaultDataSource", DataSourceBuilder.create().driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
// .url("jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test")
// .username("sa")
// .password("root")
// .build());
dataSourcesMap.put("dbkey", DataSourceBuilder.create().driverClassName("org.h2.Driver")
.url("jdbc:h2:~/test")
.username("sa")
.password("root")
.build());
}
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSource.dataSourceKey;
}
public static void setDataSource(String dataSource) {
DynamicDataSource.dataSourceKey=dataSource;
DynamicDataSource dynamicDataSource = (DynamicDataSource) SpringUtils.getBean("dataSource");
dynamicDataSource.afterPropertiesSet();
}
public static void setH2DataSource(){
DynamicDataSource.setDataSource("dbkey");
}
public static void setDefaultDataSource(){
DynamicDataSource.setDataSource("defaultDataSource");
}
public static String getDataSource() {
return DynamicDataSource.dataSourceKey;
}
//public static void clear() {
// DynamicDataSource.dataSourceKey.remove();
//}
}
//初始化时指定一个默认数据源
```@Bean
public DataSource getDefaultDataSource(){
Props props = new Props(propertiesUrl+"dataSourceConfig.properties");
DataSource build = DataSourceBuilder.create().driverClassName(props.getStr("driverClassName"))
.url(props.getStr("url"))
.username(props.getStr("username"))
.password(props.getStr("password"))
.build();
props.clear();
return build;
}
通过接口来实现数据源的变更
@PostMapping("/setDataSource")
public ResultDTO<Boolean> changeDataSource(DataSourceDTO dataSourceDTO) {
DataSource dataSource = DataSourceBuilder.create().driverClassName(dataSourceDTO.getDriverClassName())
.url(dataSourceDTO.getJdbcUrl())
.username(dataSourceDTO.getUsername())
.password(dataSourceDTO.getPassword())
.build();
DynamicDataSource.dataSourcesMap.put("defaultDataSource", dataSource);
DynamicDataSource.setDataSource("defaultDataSource");
//持久化写入
Props props = new Props();
props.setProperty("driverClassName",dataSourceDTO.getDriverClassName());
props.setProperty("url",dataSourceDTO.getJdbcUrl());
props.setProperty("username",dataSourceDTO.getUsername());
props.setProperty("password",dataSourceDTO.getPassword());
props.store(propertiesUrl+"dataSourceConfig.properties");
props.clear();
return ResultDTO.success();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyDataSource {
String value();
}
//通过注解和aop来扫描mapper层接口来实现数据源切换
@Aspect
@Order(1) //设置AOP执行顺序(需要在事务之前,否则事务只发生在默认库中)
@Component
@Slf4j
public class DataSourceAspect {
//切点
@Pointcut("execution(* com.cainiao.test.puhang.mapper.*.*(..))")
public void aspect() { }
@Before("aspect()")
private void before(JoinPoint point) throws Throwable {
try {
Class<?> aClass = point.getTarget().getClass();
MyDataSource parent = AnnotationUtils.findAnnotation(aClass, MyDataSource.class);
if (parent!=null){
DynamicDataSource.setH2DataSource();
}
} catch (Exception e) {
log.error("get datasource error ",e);
//默认选择master
DynamicDataSource.setDefaultDataSource();
}
}
@AfterReturning("aspect()")
public void after() {
DynamicDataSource.setDefaultDataSource();
}
}
总结
提示:这里对文章进行总结:
适合特定的场景,但是要做到变更数据库的时候字段和类型是统一的