开发一个SpringBoot2.0项目,能在方法中方便的切换数据库。
一、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
二、application.yml中配置数据库信息
spring:
application:
name: bd-its-deg-service
datasource:
druid:
pgdw:
url: jdbc:postgresql://192.168.235.3/dw?characterEncoding=utf-8
username: root
password: 123456#
driverClassName: org.postgresql.Driver
filters: stat
maxActive: 100
initialSize: 5
maxWait: 60000
minIdle: 20
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: "SELECT 'x'"
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
maxOpenPreparedStatements: 60
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
crawl:
url: jdbc:postgresql://192.168.235.3/crawl?characterEncoding=utf-8
username: root2
password: 666666#
driverClassName: org.postgresql.Driver
filters: stat
maxActive: 100
initialSize: 5
maxWait: 60000
minIdle: 20
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: "SELECT 'x'"
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
maxOpenPreparedStatements: 60
removeAbandoned: true
removeAbandonedTimeout: 1800
logAbandoned: true
三、生成对应的数据库bean类DynamicDataSourceConfiguration
@MapperScan(basePackages = "cn.com.bluemoon.bd.service.its.deg.dao")
@Configuration
public class DynamicDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.pgdw")
public DataSource dbPgdw() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.druid.crawl")
public DataSource dbCrawl() {
return DruidDataSourceBuilder.create().build();
}
/**
* 核心动态数据源
*
* @return 数据源实例
*/
@Bean
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setDefaultTargetDataSource(dbPgdw());
Map<Object, Object> dataSourceMap = new HashMap<>(4);
dataSourceMap.put(DataSourceKey.DB_PGDW, dbPgdw());
dataSourceMap.put(DataSourceKey.DB_CRAWL, dbCrawl());
dataSource.setTargetDataSources(dataSourceMap);
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
//此处设置为了解决找不到mapper文件的问题
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
/**
* 事务管理
*
* @return 事务管理实例
*/
@Bean
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
四、配置一个枚举类,记录数据库名
public enum DataSourceKey {
DB_PGDW,
DB_CRAWL
}
五、配置一个注解,方法中有该注解的会动态切换数据库
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
public @interface DataSource {
DataSourceKey value() default DataSourceKey.DB_PGDW;
}
DynamicDataSourceAspect.java
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {
private static final Logger LOG = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
/**
* 执行方法前更换数据源
*
* @param joinPoint 切点
* @param targetDataSource 动态数据源
*/
@Before("@annotation(targetDataSource)")
public void doBefore(JoinPoint joinPoint, DataSource targetDataSource) {
DataSourceKey dataSourceKey = targetDataSource.value();
if (dataSourceKey == DataSourceKey.DB_CRAWL) {
LOG.info(String.format("设置数据源为 %s", DataSourceKey.DB_CRAWL));
DynamicDataSourceContextHolder.set(DataSourceKey.DB_CRAWL);
} else {
LOG.info(String.format("使用默认数据源 %s", DataSourceKey.DB_PGDW));
DynamicDataSourceContextHolder.set(DataSourceKey.DB_PGDW);
}
}
/**
* 执行方法后清除数据源设置
*
* @param joinPoint 切点
* @param targetDataSource 动态数据源
*/
@After("@annotation(targetDataSource)")
public void doAfter(JoinPoint joinPoint, DataSource targetDataSource) {
LOG.info(String.format("当前数据源 %s 执行清理方法", targetDataSource.value()));
DynamicDataSourceContextHolder.clear();
}
}
DynamicDataSourceContextHolder.java
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<DataSourceKey> currentDatesource = new ThreadLocal<>();
/**
* 清除当前数据源
*/
public static void clear() {
currentDatesource.remove();
}
/**
* 获取当前使用的数据源
*
* @return 当前使用数据源的ID
*/
public static DataSourceKey get() {
return currentDatesource.get();
}
/**
* 设置当前使用的数据源
*
* @param value 需要设置的数据源ID
*/
public static void set(DataSourceKey value) {
currentDatesource.set(value);
}
}
DynamicRoutingDataSource.java
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private static final Logger LOG = LoggerFactory.getLogger(DynamicRoutingDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
LOG.info("当前数据源:{}", DynamicDataSourceContextHolder.get());
return DynamicDataSourceContextHolder.get();
}
}
具体的类如下图所示
image.png
六、用法
在service方法中添加上配置的注解
@Override
@DataSource(DataSourceKey.DB_PGDW)
public String exportDataTable(String param) {
log.info("切换数据源为PG dw库 测试是否被调用:" + param + ">>>>>>>>>" + param);
// 切换数据源为PG dw库
}
当然,也可以不使用注解,可以在同一个方法中使用不同的数据库
@Override
public String exportDataTable(String param) {
DynamicDataSourceContextHolder.set(DataSourceKey.DB_PGDW);
log.info("切换数据源为PG dw库 测试是否被调用:" + param + ">>>>>>>>>" + param);
// 切换数据源为PG dw库
if(......){
DynamicDataSourceContextHolder.set(DataSourceKey.DB_CRAWL);
}
}
参考文章:https://blog.csdn.net/u013360850/article/details/78861442
网友评论