SpringBoot多数据配置实现
1. 应用场景
在实际项目开发中依赖的数据库可能不知一个,可能有Mysql的也可能有Oracle等。这时候需要我没项目配置多个数据库,实现访问不同数据来源。下面就来说说如何实现使用多种数据库连接。
2.实现方式
话不多说,可以想到的有以下几种:
(1)动态的切换数据库访问
(2)指定包路径访问不同的数据库
3.实现动态切换数据库
通过在application.properties配置文件中配置多个数据库,然后在调用方法时动态的切换数据库连接,来跟据数据来源切换到不同的数据库。如何切换呢?自定义一个注解,在调用的方法上写上该注解,在注解上指明数据库,在每次调用方法利用反射获取到方法上的注解,根据注解上的数据库来动态的切换到相应的数据连接上。
直接上干货!首先编写自定义注解。
- 实现思路
- 编码实现
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author: william
* @Description: TODO
* @date: 2018年5月25日 上午11:31:44
* @version: v1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Datasource {
String value() default "datasource1";
}
编写数据库连接默认类
/**
* @author: william
* @Description: TODO
* @date: 2018年5月25日 上午11:44:45
* @version: v1.0.0
*/
public class DataSourceContextHolder {
//默认数据源
public static final String DEFAULT_DS = "datasource1";
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();
}
}
编辑数据库动态切换类
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @author: william
* @Description: TODO
* @date: 2018年5月25日 上午11:57:36
* @version: v1.0.0
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
System.out.println("数据源为"+DataSourceContextHolder.getDB());
return DataSourceContextHolder.getDB();
}
}
编写数据库配置类,将application.properties中的数据库配置注入到上下文中
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author: william
* @Description: 多数据源配置
* @date: 2018年5月25日上午11:33:33
* @version: v1.0.0
*/
@Configuration
public class DataSourceConfig {
//数据源1
@Bean(name = "datasource1")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource dataSource1() {
DataSource ds = DataSourceBuilder.create().type(DruidDataSource.class).build();
return ds;
}
//数据源2
@Bean(name = "datasource2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSource2() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(dataSource1());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap<Object, Object>();
dsMap.put("datasource1", dataSource1());
dsMap.put("datasource2", dataSource2());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 配置@Transactional注解事物
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
最后是实现数据库动态切换的切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author: william
* @Description: 使用AOP切面方式动态的切换数据源
* @date: 2018年5月25日 下午1:51:27
* @version: v1.0.0
*/
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(Datasource)")
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);
// 判断是否存在@Datasource注解
if (method.isAnnotationPresent(Datasource.class)) {
Datasource annotation = method.getAnnotation(Datasource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
//切换数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("@annotation(Datasource)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
然后我们再看看数据库配置
spring.datasource.db1.url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
spring.datasource.db1.driverClassName=com.mysql.jdbc.Driver
spring.datasource.db1.username=root
spring.datasource.db1.password=123456
spring.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.db1.druid.initial-size=5
spring.datasource.db1.druid.min-idle=5
spring.datasource.db1.druid.max-active=20
spring.datasource.db1.druid.test-on-borrow=true
spring.datasource.db1.druid.stat-view-servlet.allow=true
spring.datasource.db2.url=jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
spring.datasource.db2.driverClassName=com.mysql.jdbc.Driver
spring.datasource.db2.username=root
spring.datasource.db2.password=123456
spring.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.db2.druid.initial-size=5
spring.datasource.db2.druid.min-idle=5
spring.datasource.db2.druid.max-active=20
spring.datasource.db2.druid.test-on-borrow=true
spring.datasource.db2.druid.stat-view-servlet.allow=true
代码还是比较简单易懂的。