1、pom 导入依赖
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
2、多个数据源配置 以 mysql 5 为例
spring:
datasource:
druid:
master:
url: jdbc:mysql://ip:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&&serverTimezone=GMT%2B8&useSSL=false
username: root
password: root
second:
url: jdbc:mysql://ip2:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&&serverTimezone=GMT%2B8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
3、配置数据源 默认连接
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据源配置类
*/
@Configuration
@MapperScan("com.xxx.xxx.mapper")
public class DruidConfig {
/**
* 主库数据源bean,和spring.datasource.druid.master配置绑定
*
* @return
*/
@Bean(name = CommonConstant.MASTER)
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDataSource() {
DruidDataSource master = DruidDataSourceBuilder.create().build();
return master;
}
/**
* 数据库2
* @return
*/
@Bean(name = CommonConstant.second)
@ConfigurationProperties("spring.datasource.druid.second")
public DataSource secondDataSource() {
DruidDataSource second= DruidDataSourceBuilder.create().build();
return second;
}
/**
* 动态数据源bean
*
* @return
*/
@Bean
@Primary
public DynamicDataSource dynamicDataSource() {
//创建一个存放数据源的map
Map<Object, Object> dataSourceMap = new HashMap<>(2);
//将上述两个数据源存放到map中
dataSourceMap.put(CommonConstant.MASTER, masterDataSource());
dataSourceMap.put(CommonConstant.second, secondDataSource());
//设置动态数据源,默认为master配置的数据源,并指定数据源的map
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
System.out.println("设置默认数据源");
dynamicDataSource.setTargetDataSources(dataSourceMap);
//将数据源信息备份在defineTargetDataSources中
dynamicDataSource.setDefineTargetDataSources(dataSourceMap);
return dynamicDataSource;
}
}
4、数据源配置常量类
/**
* 数据源配置常量类
*/
public class CommonConstant {
/**
* 默认数据源标识
*/
public static final String MASTER = "master";
/**
* 从数据源标识
*/
public static final String second= "second";
}
5、注解类
import java.lang.annotation.*;
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Ds
{
/**
* 切换数据源名称
*/
public String value() default CommonConstant.MASTER;
}
6、环绕通知
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Aspect
@Component
public class DataSourceAspect {
// 设置Ds注解的切点表达式,所有Ds都会触发当前环绕通知
@Pointcut("@annotation(com.xxx.xxx.config.druid.Ds)")
public void dynamicDataSourcePointCut(){
}
//环绕通知
@Around("dynamicDataSourcePointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
//获取数据源的key
String key = getDefineAnnotation(joinPoint).value();
//将数据源设置为该key的数据源
DynamicDataSourceHolder.setDynamicDataSourceKey(key);
try {
return joinPoint.proceed();
} finally {
//使用完成后切回master
DynamicDataSourceHolder.removeDynamicDataSourceKey();
}
}
/**
* 先判断方法的注解,后判断类的注解,以方法的注解为准
* @param joinPoint
* @return
*/
private Ds getDefineAnnotation(ProceedingJoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Ds dataSourceAnnotation = methodSignature.getMethod().getAnnotation(Ds.class);
if (Objects.nonNull(methodSignature)) {
return dataSourceAnnotation;
} else {
Class<?> dsClass = joinPoint.getTarget().getClass();
return dsClass.getAnnotation(Ds.class);
}
}
}
7、数据源信息处理
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DynamicDataSource extends AbstractRoutingDataSource {
//备份所有数据源信息,
private Map<Object, Object> defineTargetDataSources;
/**
* 返回当前线程需要用到的数据源bean
*/
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDynamicDataSourceKey();
}
}
8、数据源切换处理类
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
/**
* 数据源切换处理类
*
*/
@Slf4j
public class DynamicDataSourceHolder {
/**
* 为每个线程存放当前数据源的ThreadLocal
*/
private static final ThreadLocal<String> DYNAMIC_DATASOURCE_KEY = new ThreadLocal<>();
/**
* 为当前线程切换数据源
*/
public static void setDynamicDataSourceKey(String key) {
// log.info("数据源切换key:{}", key);
DYNAMIC_DATASOURCE_KEY.set(key);
}
/**
* 获取动态数据源的名称,默认情况下使用mater数据源
*/
public static String getDynamicDataSourceKey() {
String key = DYNAMIC_DATASOURCE_KEY.get();
if (ObjectUtils.isEmpty(key)) {
key = CommonConstant.MASTER;
}
// log.info("获取数据源,key:{}", key);
return key;
}
/**
* 将ThreadLocal置空,移除当前数据源
*/
public static void removeDynamicDataSourceKey() {
// log.info("移除数据源:{}", DYNAMIC_DATASOURCE_KEY.get());
DYNAMIC_DATASOURCE_KEY.remove();
}
}
9、以上就可以使用多个数据源自由切换了
// 切换数据源
DynamicDataSourceHolder.setDynamicDataSourceKey(CommonConstant.second);
// 切回主数据源
DynamicDataSourceHolder.setDynamicDataSourceKey(CommonConstant.MASTER);
10、如需配置动态数据源 如下
数据源对象类
/**
* 数据源对象类
*/
public class DataSourceInfo {
private String userName;
private String passWord;
private String url;
private String dataSourceKey;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDataSourceKey() {
return dataSourceKey;
}
public void setDataSourceKey(String dataSourceKey) {
this.dataSourceKey = dataSourceKey;
}
@Override
public String toString() {
return "DataSourceInfo{" +
"userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
", url='" + url + '\'' +
", dataSourceKey='" + dataSourceKey + '\'' +
'}';
}
}
11、数据源配置工具类
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.Map;
/**
* 数据源管理工具类
*/
@Slf4j
@Component
public class DataSourceUtil {
@Resource
DynamicDataSource dynamicDataSource;
/**
* 测试数据源是否可用,如果可用即直接返回
* @param dataSourceInfo
* @return
* @throws SQLException
*/
public DruidDataSource createDataSourceConnection(DataSourceInfo dataSourceInfo) throws SQLException {
//创建数据源对象
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceInfo.getUrl());
druidDataSource.setUsername(dataSourceInfo.getUserName());
druidDataSource.setPassword(dataSourceInfo.getPassWord());
druidDataSource.setBreakAfterAcquireFailure(true);
druidDataSource.setConnectionErrorRetryAttempts(0);
try {
//尝试连接数据源
druidDataSource.getConnection(2000);
log.info("数据源:{}连接成功", JSONUtils.toJSONString(dataSourceInfo));
return druidDataSource;
} catch (SQLException e) {
log.error("数据源 {} 连接失败,用户名:{},密码 {}",dataSourceInfo.getUrl(),dataSourceInfo.getUserName(),dataSourceInfo.getPassWord());
return null;
}
}
/**
* 将外部数据源存到dynamicDataSource并调用afterPropertiesSet刷新
* @param druidDataSource
* @param dataSourceName
*/
public void addDefineDynamicDataSource(DruidDataSource druidDataSource, String dataSourceName){
Map<Object, Object> defineTargetDataSources = dynamicDataSource.getDefineTargetDataSources();
//存到defineTargetDataSources这个map中
defineTargetDataSources.put(dataSourceName, druidDataSource);
dynamicDataSource.setTargetDataSources(defineTargetDataSources);
//调用afterPropertiesSet重新遍历map中的数据源键值对存到resolvedDataSources中
dynamicDataSource.afterPropertiesSet();
}
}
12、使用
DataSourceInfo dataSourceInfo = new DataSourceInfo();
dataSourceInfo.setUrl("url");
dataSourceInfo.setPassWord("password");
dataSourceInfo.setUserName("username");
dataSourceInfo.setDataSourceKey("xxx");
DataSourceUtil dataSourceUtil = new DataSourceUtil();
DruidDataSource dataSourceConnection = dataSourceUtil.createDataSourceConnection(dataSourceInfo);
dataSourceUtil.addDefineDynamicDataSource(dataSourceConnection,dataSourceInfo.getDataSourceKey());
//切换
DynamicDataSourceHolder.setDynamicDataSourceKey(dataSourceInfo.getDataSourceKey());
原文地址:不记得了,如有知情,请联系我