开发项目的时候一个项目要访问不同的数据库,所以要用到双数据源
首先配置类:
url 账号密码自行改。我的是两种不同类型的数据库,相同的也是一样的。
datasource:
type: com.alibaba.druid.pool.DruidDataSource
db:
jdbc-url: jdbc:postgresql://172.16.20.58:5432/zrzy_gis
username: ${MYSQL-USER:postgres}
password: ${MYSQL-PWD:root}
driver-class-name: org.postgresql.Driver
hikari:
maximum-pool-size: 25
auto-commit: true
minimum-idle: 5
idle-timeout: 30000
pool-name: DatebookHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: select 1
db2:
jdbc-url: jdbc:mysql://${MYSQL-HOST:okayx-mysql}:${MYSQL-PORT:3306}/${MYSQL-DB:okayxx_gis_support}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: ${MYSQL-USER:root}
password: ${MYSQL-PWD:root}
我们用aop实现 ,所以先导入aop的包和aspectj的包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
我们需要自己加载数据源,所以run方法里面排除数据库加载类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GeoApiApplication {
public static void main(String[] args) {
SpringApplication.run(GeoApiApplication.class, args);
}
}
数据源加载类,加载两个数据源的配置
/**
* @Author: ch
* @Date: 2018/6/27 11:06
* @Description: 加载数据库配置
*/
@Configuration
public class DataSourceConfig {
@Bean(name = "db")
@ConfigurationProperties(prefix = "spring.datasource.db")
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSource2() {
return DataSourceBuilder.create().build();
}
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
*
* @return
*/
@Primary
@Bean(name = "dynamicDS1")
public DataSource dataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSource1());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap(5);
dsMap.put("db", dataSource1());
dsMap.put("db2", dataSource2());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 配置@Transactional注解事物
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
设置数据源类
public class DataSourceContextHolder {
/**
* 默认数据源
*/
public static final String DEFAULT_DS = "db";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
public static void setDB(String dbType) {
contextHolder.set(dbType);
}
// 获取数据源名
public static String getDB() {
return (contextHolder.get());
}
// 清除数据源名
public static void clearDB() {
contextHolder.remove();
}
}
获取数据源
/**
* @Author: ch
* @Date: 2018/6/27 11:40
* @Description:
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDB();
}
}
aop切面注解,默认db。
/**
* @Author: ch
* @Date: 2018/6/27 11:47
* @Description:
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD
})
public @interface DS {
String value() default "db";
}
aspect切面类
/**
* @Author: ch
* @Date: 2018/6/27 11:48
* @Description:
*/
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(DS)")
public void beforeSwitchDS(JoinPoint point){
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DS注解
if (method.isAnnotationPresent(DS.class)) {
DS annotation = method.getAnnotation(DS.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("@annotation(DS)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
测试 :只需要在方法上加注解 @DS("db2")就可以切换数据源
/**
* 分页查询
* @param page 分页对象
* @param gisSupportTest 模型管理
* @return
*/
@DS("db2")
@ApiOperation(value = "分页查询", notes = "分页查询")
@GetMapping("/page" )
public R getGisSupportTestPage(Page page, GisSupportTest gisSupportTest) {
return R.ok(gisSupportTestService.page(page, Wrappers.query(gisSupportTest)));
}