Druid数据库多数据源
Spring的多数据源支持—AbstractRoutingDataSource,AbstractRoutingDataSource定义了抽象的determineCurrentLookupKey方法,子类实现此方法,来确定要使用的数据源
Druid 实现多数据源支持,核心是Overwrite AbstractRoutingDataSource 的 determineCurrentLookupKey 方法
publicabstractclassAbstractRoutingDataSourceextendsAbstractDataSourceimplementsInitializingBean{protectedDataSourcedetermineTargetDataSource(){Assert.notNull(this.resolvedDataSources,"DataSource router not initialized");Object lookupKey =determineCurrentLookupKey();DataSource dataSource =this.resolvedDataSources.get(lookupKey);if(dataSource ==null&&(this.lenientFallback || lookupKey ==null)){
dataSource =this.resolvedDefaultDataSource;}if(dataSource ==null){thrownewIllegalStateException("Cannot determine target DataSource for lookup key ["+ lookupKey +"]");}return dataSource;}// 确定当前要使用的数据源protectedabstractObjectdetermineCurrentLookupKey();}
配置多数据源
以springboot框架为基础使用aop注解的方式依赖Druid配置多数据源
1.添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- aop注解实现aspectjweaver依赖 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><!-- mybatis-spring-boot-starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency>
2.配置Druid属性
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
first:
url: jdbc:mysql://localhost:3306/***?useUnicode=true&characterEncoding=utf- 8&serverTimezone=UTC
username: root
password: *****
second:
enable: true
url: jdbc:mysql://localhost:3306/***?useUnicode=true&characterEncoding=utf- 8&serverTimezone=UTC
username: root
password: *****
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 控制台管理用户名和密码
login-username: admin
login-password: 123456
#配置监控统计拦截的filters:stat:监控统计、self4j(使用log4j的记得导入log4j的依赖):日志记录、 wall:防御sql注入 此处配置不能遗漏服务sql监控台不能监控sql
filters: stat,wall,log4j2
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
enabled: true
config:
multi-statement-allow: true
3.配置动态数据源
继承AbstractRoutingDataSource重写determineCurrentLookupKey()方法
/**
* 动态数据源
*/publicclassDynamicDatesourceextendsAbstractRoutingDataSource{publicDynamicDatesource(DataSource dataSource,HashMap<Object,Object> map){super.setDefaultTargetDataSource(dataSource);super.setTargetDataSources(map);super.afterPropertiesSet();}/**
* 获取key指定数据源
* @return
*/@OverrideprotectedObjectdetermineCurrentLookupKey(){returnDynamicDateSourceCut.getLocal();}}
配置数据源
//配置数据源
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.first")
public DataSource firstDataSource(DruidSourceProperties druidSourceProperties){
return druidSourceProperties.dataSource(new DruidDataSourceWrapper());
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.second")
@ConditionalOnProperty(prefix ="spring.datasource.second",name ="enable",havingValue = "true")
public DataSource secondDataSource(DruidSourceProperties druidSourceProperties){
return druidSourceProperties.dataSource(new DruidDataSourceWrapper());
}
@Bean
@Primary//在多数据源的时候,使用@Primary注解用于指定其中一个作为主数据源
public DynamicDatesource setDymaicDatesource(DataSource firstDataSource){
HashMap<Object, Object> map = new HashMap<>();
map.put(DateSourceType.FIRST.name(),firstDataSource);
setDataSource(map,DateSourceType.SECOND.name(),"secondDataSource");
return new DynamicDatesource(firstDataSource,map);
}
/**
* 设置数据源
*
* @param targetDataSources 备选数据源集合
* @param sourceName 数据源名称
* @param beanName bean名称
*/
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName){
try {
DataSource dataSource = SpringUtils.getBean(beanName);
targetDataSources.put(sourceName, dataSource);
} catch (Exception e){
}
}
}
4.配置数据源切换
packagecom.example.springboot.data;/**
*数据源切换 保存每个数据源指定的lookupKey
*/publicclassDynamicDateSourceCut{/**
* 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/privatestaticThreadLocal<String> threadLocal=newThreadLocal<>();/**
* 设置数据源的变量
*/publicstaticvoidsetLocal(String local){
threadLocal.set(local);}/**
* 获得数据源的变量
*/publicstaticStringgetLocal(){return threadLocal.get();}/**
* 清空数据源变量
*/publicstaticvoidclearLocl(){
threadLocal.remove();}}
5.定义aop切面实现
/**
* 定义数据源切面
*/@Aspect@ComponentpublicclassDateSourceAspect{privatestaticfinalLogger log=LoggerFactory.getLogger(DateSourceAspect.class);/**
* 定义切点 使用注解
* @within类注解
* @annotation方法注解
*/@Pointcut("@annotation(com.example.springboot.aspect.DateSource)"+"||@within(com.example.springboot.aspect.DateSource)")publicvoidPintCut(){}/**
* 通知使用环绕的通知方法
*/@Around("PintCut()")publicObjectResovePoint(ProceedingJoinPoint point)throwsThrowable{//获取注解DateSource dateSource =getDateSource(point);if(dateSource!=null){DynamicDateSourceCut.setLocal(dateSource.value().name());}try{//执行方法return point.proceed();}finally{// 销毁数据源 在执行方法之后DynamicDateSourceCut.clearLocl();}}/**
* 获取注解
*/protectedDateSourcegetDateSource(ProceedingJoinPoint point){MethodSignature signature =(MethodSignature) point.getSignature();//获取方法或方法类型上的注解DateSource annotation;//获取class类型上注解
annotation=AnnotationUtils.findAnnotation(signature.getDeclaringType(),DateSource.class);if(annotation==null){
annotation =AnnotationUtils.findAnnotation(signature.getMethod(),DateSource.class);}return annotation;}}
定义的注解和注解值
/**
* 定义注解
*/@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceDateSource{DateSourceTypevalue()defaultDateSourceType.FIRST;}/**
*使用枚举定义注解的值
*/publicenumDateSourceType{//默认数据库FIRST,SECOND;}
版权归原作者 Mr_ming_a_probie 所有, 如有侵权,请联系我们删除。