一宋渔、主要依賴
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.4.RELEASE</version><relativePath/></parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.1.4.RELEASE</version></dependency>dependency>
? ? <groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency>
二、yml
# 數(shù)據(jù)源配置
spring:
? ? datasource:
? ? ? ? type: com.alibaba.druid.pool.DruidDataSource
? ? ? ? driverClassName: com.mysql.jdbc.Driver
? ? ? ? druid:
? ? ? ? ? ? # 主庫數(shù)據(jù)源
? ? ? ? ? ? master:
? ? ? ? ? ? ? ? url: jdbc:mysql://127.0.0.1:3306/master?characterEncoding=UTF-8? ? ? ? ? ? ? ? username: root
? ? ? ? ? ? ? ? password: root
? ? ? ? ? ? #樹熊數(shù)據(jù)源
? ? ? ? ? ? slave:
? ? ? ? ? ? ? ? enabled : true? ? ? ? ? ? ? ? url: jdbc:mysql:////127.0.0.1:3306/slave?characterEncoding=UTF-8? ? ? ? ? ? ? ? username: root
? ? ? ? ? ? ? ? password: root
? ? ? ? ? ? # 初始連接數(shù)
? ? ? ? ? ? initial-size: 10? ? ? ? ? ? # 最大連接池數(shù)量
? ? ? ? ? ? max-active: 100? ? ? ? ? ? # 最小連接池數(shù)量
? ? ? ? ? ? min-idle: 10? ? ? ? ? ? # 配置獲取連接等待超時的時間
? ? ? ? ? ? max-wait: 60000? ? ? ? ? ? # 打開PSCache惊科,并且指定每個連接上PSCache的大小
? ? ? ? ? ? pool-prepared-statements:true? ? ? ? ? ? max-pool-prepared-statement-per-connection-size: 20? ? ? ? ? ? # 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接含衔,單位是毫秒
? ? ? ? ? ? timeBetweenEvictionRunsMillis: 60000? ? ? ? ? ? # 配置一個連接在池中最小生存的時間蹄咖,單位是毫秒
? ? ? ? ? ? min-evictable-idle-time-millis: 300000? ? ? ? ? ? validation-query: SELECT 1 FROM DUAL
? ? ? ? ? ? test-while-idle:true? ? ? ? ? ? test-on-borrow:false? ? ? ? ? ? test-on-return:false? ? ? ? ? ? stat-view-servlet:
? ? ? ? ? ? ? ? enabled: true? ? ? ? ? ? ? ? url-pattern: /druid/*? ? ? ? ? ? filter:
? ? ? ? ? ? ? ? stat:
? ? ? ? ? ? ? ? ? ? log-slow-sql: true
? ? ? ? ? ? ? ? ? ? slow-sql-millis: 1000
? ? ? ? ? ? ? ? ? ? merge-sql: false
? ? ? ? ? ? ? ? wall:
? ? ? ? ? ? ? ? ? ? config:
? ? ? ? ? ? ? ? ? ? ? ? multi-statement-allow: true
三泽示、實現(xiàn)
3.1、@DataSource和DataSourceType
/** * 數(shù)據(jù)源
* @author DUCHONG
*/publicenum DataSourceType
{
? ? /**? ? * 主庫
? ? */? ? MASTER,
? ? /**? ? * 從庫
? ? */? ? SLAVE
}
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 自定義多數(shù)據(jù)源切換注解
*
* @author DUCHONG
*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)public@interface DataSource
{
? ? /**? ? * 切換數(shù)據(jù)源名稱
? ? */publicDataSourceType value()default DataSourceType.MASTER;
}
3.2腥放、DynamicDataSourceContextHolder
import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 數(shù)據(jù)源切換處理
*
* @author DUCHONG
*/publicclass DynamicDataSourceContextHolder
{
? ? publicstaticfinalLogger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
? ? /**? ? * 使用ThreadLocal維護變量泛啸,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,
? ? *? 所以每一個線程都可以獨立地改變自己的副本秃症,而不會影響其它線程所對應的副本候址。
? ? */privatestaticfinalThreadLocal CONTEXT_HOLDER =newThreadLocal<>();
? ? /**? ? * 設置數(shù)據(jù)源的變量
? ? */publicstaticvoid setDateSourceType(String dsType)
? ? {
? ? ? ? log.info("切換到{}數(shù)據(jù)源", dsType);
? ? ? ? CONTEXT_HOLDER.set(dsType);
? ? }
? ? /**? ? * 獲得數(shù)據(jù)源的變量
? ? */publicstatic String getDateSourceType()
? ? {
? ? ? ? return CONTEXT_HOLDER.get();
? ? }
? ? /**? ? * 清空數(shù)據(jù)源變量
? ? */publicstaticvoid clearDateSourceType()
? ? {
? ? ? ? CONTEXT_HOLDER.remove();
? ? }
}
3.3、繼承AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;import javax.sql.DataSource;import java.util.Map;/** * 動態(tài)數(shù)據(jù)源
*
* @author DUCHONG
*/publicclassDynamicDataSourceextends AbstractRoutingDataSource
{
? ? publicDynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources)
? ? {
? ? ? ? super.setDefaultTargetDataSource(defaultTargetDataSource);
? ? ? ? super.setTargetDataSources(targetDataSources);
? ? ? ? super.afterPropertiesSet();
? ? }
? ? @Override
? ? protected Object determineCurrentLookupKey()
? ? {
? ? ? ? return DynamicDataSourceContextHolder.getDateSourceType();
? ? }
}
3.4种柑、定義切面
import com.starfast.admin.common.annotation.DataSource;import com.starfast.admin.datasource.DynamicDataSourceContextHolder;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.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import java.lang.reflect.Method;/** * 多數(shù)據(jù)源處理
* @author DUCHONG
*/@Aspect
@Order(1)
@Componentpublicclass DataSourceAspect
{
? ? protectedLogger logger = LoggerFactory.getLogger(getClass());
? ? @Pointcut("@annotation(com.duchong.common.annotation.DataSource)")
? ? publicvoid dsPointCut()
? ? {
? ? }
? ? @Around("dsPointCut()")
? ? publicObject around(ProceedingJoinPoint point)throws Throwable
? ? {
? ? ? ? MethodSignature signature = (MethodSignature) point.getSignature();
? ? ? ? Method method = signature.getMethod();
? ? ? ? DataSource dataSource = method.getAnnotation(DataSource.class);
? ? ? ? if(null!=dataSource)
? ? ? ? {
? ? ? ? ? ? DynamicDataSourceContextHolder.setDateSourceType(dataSource.value().name());
? ? ? ? }
? ? ? ? try? ? ? ? {
? ? ? ? ? ? return point.proceed();
? ? ? ? }
? ? ? ? finally? ? ? ? {
? ? ? ? ? ? // 銷毀數(shù)據(jù)源 在執(zhí)行方法之后? ? ? ? ? ? DynamicDataSourceContextHolder.clearDateSourceType();
? ? ? ? }
? ? }
}
3.5岗仑、@Configuration
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;import com.starfast.admin.common.enums.DataSourceType;import com.starfast.admin.datasource.DynamicDataSource;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;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;/** * druid 配置多數(shù)據(jù)源
*
* @author DUCHONG
*/@Configurationpublicclass DruidConfig
{
? ? @Bean
? ? @ConfigurationProperties("spring.datasource.druid.master")
? ? public DataSource masterDataSource()
? ? {
? ? ? ? return DruidDataSourceBuilder.create().build();
? ? }
? ? @Bean
? ? @ConfigurationProperties("spring.datasource.druid.slave")
? ? @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
? ? public DataSource slaveDataSource()
? ? {
? ? ? ? return DruidDataSourceBuilder.create().build();
? ? }
? ? @Bean(name = "dynamicDataSource")
? ? @Primary
? ? public DynamicDataSource dataSource()
? ? {
? ? ? ? Map targetDataSources =newHashMap<>();
? ? ? ? targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource());
? ? ? ? targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource());
? ? ? ? returnnew DynamicDataSource(masterDataSource(), targetDataSources);
? ? }
}
3.6、使用
需要切換數(shù)據(jù)源的方法上加
@DataSource(value = DataSourceType.SLAVE)