一、枚举类
这里面写了要用的数据库
public enum DatabaseType {
demo_cangku1,
demo_cangku2
}
二、动态数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<DataSourceType>();
public static void setDataSourceType(DataSourceType dataSourceType) {
contextHolder.set(dataSourceType);
}
public static DataSourceType getDataSourceType() {
return contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSourceType();
}
}
三、数据源配置
import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
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.annotation.EnableTransactionManagement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableTransactionManagement // 启用事务
public class DruidDBConfig {
final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 设置数据源
*
* @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@Aautowire注解报错
* @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)
*/
@Bean
@Primary
public DynamicDataSource dataSource(
@Value("${spring.datasource.primary.url}") String primaryUrl,
@Value("${spring.datasource.primary.username}") String primaryUsername,
@Value("${spring.datasource.primary.password}") String primaryPassword,
@Value("${spring.datasource.secondary.url}") String secondaryUrl,
@Value("${spring.datasource.secondary.username}") String secondaryUsername,
@Value("${spring.datasource.secondary.password}") String secondaryPassword
) {
//数据源-1
DruidDataSource primaryDataSource = getDruidDataSource();
primaryDataSource.setUrl(primaryUrl);
primaryDataSource.setUsername(primaryUsername);
primaryDataSource.setPassword(primaryPassword);
//数据源-2
DruidDataSource secondaryDataSource = getDruidDataSource();
secondaryDataSource.setUrl(secondaryUrl);
secondaryDataSource.setUsername(secondaryUsername);
secondaryDataSource.setPassword(secondaryPassword);
Map<Object, Object> mapDataSources = new HashMap<>();
mapDataSources.put(DataSourceType.demo_cangku1, primaryDataSource);
mapDataSources.put(DataSourceType.demo_cangku2, secondaryDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(mapDataSources);// 该方法是AbstractRoutingDataSource的方法
dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认的datasource设置为primaryDataSource
return dataSource;
}
//配置事务管理器
@Bean("txManager")
public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
@Value("${spring.datasource.initialSize}")
private Integer initialSize;
@Value("${spring.datasource.minIdle}")
private Integer minIdle;
@Value("${spring.datasource.maxActive}")
private Integer maxActive;
@Value("${spring.datasource.maxWait}")
private Integer maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private Boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private Boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private Boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private Boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private Integer maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.connectionProperties}")
private String connectionProperties;
@Value("${spring.datasource.useGlobalDataSourceStat}")
private Boolean useGlobalDataSourceStat;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
private DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
druidDataSource.setValidationQuery(validationQuery);
druidDataSource.setTestWhileIdle(testWhileIdle);
druidDataSource.setTestOnBorrow(testOnBorrow);
druidDataSource.setTestOnReturn(testOnReturn);
druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
druidDataSource.setConnectionProperties(connectionProperties);
druidDataSource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
druidDataSource.setDriverClassName(driverClassName);
return druidDataSource;
}
}
application.yml数据源参数配置
spring:
application:
name: callCollectionSystemService
index: 1
profiles:
active: local
datasource:
driverClassName: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 5
minIdle: 5
maxActive: 50
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j2
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
useGlobalDataSourceStat: true
messages:
basename: messages/messages
四、数据源切面
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@Aspect//使用@Aspect注解将一个java类定义为切面类
@Order(5)
@Configuration
public class DataSourceAop {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(public * com.test.CallCollectionSystemService.dao.demo_cangku1..*.*(..))")
public void demo_cangku1() {
}
@Before("cangku1()")
public void cangku1_doBefore(JoinPoint joinPoint) throws Throwable {
if(null == DynamicDataSource.getDataSourceType() || !DynamicDataSource.getDataSourceType().equals(DataSourceType.demo_cangku1)) {
DynamicDataSource.setDataSourceType(DataSourceType.demo_cangku1);
}
}
@Pointcut("execution(public * com.test.CallCollectionSystemService.dao.cangku2..*.*(..))")
public void cangku2() {
}
@Before("cangku2()")
public void cangku2_doBefore(JoinPoint joinPoint) throws Throwable {
if(null == DynamicDataSource.getDataSourceType() || !DynamicDataSource.getDataSourceType().equals(DataSourceType.cangku2)) {
DynamicDataSource.setDataSourceType(DataSourceType.cangku2);
}
}
}