1.POM dependence
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
2. Profiles
@Data
@Component
@ConfigurationProperties("spring.datasource.druid")
public class DruidDataSourceProperties {
private String username;
private String password;
private String url;
private String driverClassName;
}
这里注意,yml中存放在默认的一个数据源,其他数据源是存放在数据库的下面会说明表结构以及例子
/**
* @author lengleng
* @date 2019-03-31
* <p>
* 动态数据源切换配置
*/
@Slf4j
@Configuration
@AllArgsConstructor
public class DynamicDataSourceConfig {
private final Map<Object, Object> dataSourceMap = new HashMap<>(8);
private final DruidDataSourceProperties dataSourceProperties;
private final StringEncryptor stringEncryptor;
@Bean("dynamicDataSource")
public DynamicDataSource dataSource() {
DynamicDataSource ds = new DynamicDataSource();
DruidDataSource cads = new DruidDataSource();
cads.setUrl(dataSourceProperties.getUrl());
cads.setDriverClassName(dataSourceProperties.getDriverClassName());
cads.setUsername(dataSourceProperties.getUsername());
cads.setPassword(dataSourceProperties.getPassword());
ds.setDefaultTargetDataSource(cads);
dataSourceMap.put(0, cads);
ds.setTargetDataSources(dataSourceMap);
return ds;
}
/**
* 组装默认配置的数据源,查询数据库配置
*/
@PostConstruct
public void init() {
DriverManagerDataSource dds = new DriverManagerDataSource();
dds.setUrl(dataSourceProperties.getUrl());
dds.setDriverClassName(dataSourceProperties.getDriverClassName());
dds.setUsername(dataSourceProperties.getUsername());
dds.setPassword(dataSourceProperties.getPassword());
List<Map<String, Object>> dbList = new JdbcTemplate(dds).queryForList(DataSourceConstants.QUERY_DS_SQL);
log.info("开始 -> 初始化动态数据源");
Optional.of(dbList).ifPresent(list -> list.forEach(db -> {
log.info("数据源:{}", db.get(DataSourceConstants.DS_NAME));
DruidDataSource ds = new DruidDataSource();
ds.setUrl(String.valueOf(db.get(DataSourceConstants.DS_JDBC_URL)));
ds.setDriverClassName(Driver.class.getName());
ds.setUsername((String) db.get(DataSourceConstants.DS_USER_NAME));
String decPwd = stringEncryptor.decrypt((String)db.get(DataSourceConstants.DS_USER_PWD));
ds.setPassword(decPwd);
dataSourceMap.put(db.get(DataSourceConstants.DS_ROUTE_KEY), ds);
}));
log.info("完毕 -> 初始化动态数据源,共计 {} 条", dataSourceMap.size());
}
/**
* 重新加载数据源配置
*/
public Boolean reload() {
init();
DynamicDataSource dataSource = dataSource();
dataSource.setTargetDataSources(dataSourceMap);
dataSource.afterPropertiesSet();
return Boolean.FALSE;
}
}
/**
* @author lengleng
* @date 2019-04-01
* <p>
* 数据源相关常量
*/
public interface DataSourceConstants {
/**
* 查询数据源的SQL
*/
String QUERY_DS_SQL = "select * from gen_datasource_conf where del_flag = 0";
/**
* 数据源名称
*/
String DS_NAME = "name";
/**
* jdbcurl
*/
String DS_JDBC_URL = "url";
/**
* 用户名
*/
String DS_USER_NAME = "username";
/**
* 密码
*/
String DS_USER_PWD = "password";
}
/*
* @Date : 2019/10/18 11:29
* @auhtor : bei
* @description : 数据源常量
*/
public class DataSourceConstant {
// 商家数据源id
public static Integer BUS_DATASOURCE_ID = 1;
// 平台方数据源id
public static Integer PLA_DATASOURCE_ID = 2;
}
/*
* @Date : 2019/10/18 11:29
* @auhtor : bei
* @description : 数据源常量
*/
public enum DataSourceEnums {
// 商家数据源
BUS_DATASOURCE_ID(DataSourceConstant.BUS_DATASOURCE_ID),
// 平台方数据源id
PLA_DATASOURCE_ID(DataSourceConstant.PLA_DATASOURCE_ID);
// 数据源存放在数据库的id
private int value;
DataSourceEnums(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
}
/**
* 多数据源处理aop
*
* @author bei
*/
@Aspect
@Order(1)
@AllArgsConstructor
public class DataSourceAspect
{
@SneakyThrows
@Around("@annotation(dataSource)")
public Object around(ProceedingJoinPoint point, DataSource dataSource)
{
if (ObjectUtil.isNotNull(dataSource.value()))
{
DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().getValue());
}
try
{
return point.proceed();
}
finally
{
// 销毁数据源 在执行方法之后
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
}
/**
* @author lengleng
* @date 2019-05-18
* <p>
* 根据当前线程来选择具体的数据源
*/
@UtilityClass
public class DynamicDataSourceContextHolder {
private final ThreadLocal<Integer> CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 提供给AOP去设置当前的线程的数据源的信息
*
* @param dataSourceType
*/
public void setDataSourceType(Integer dataSourceType) {
CONTEXT_HOLDER.set(dataSourceType);
}
/**
* 使用默认的数据源
*
*/
public void clearDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
/*
* @Date : 2019/10/18 1:06
* @auhtor : bei
* @description : 切换数据源注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
DataSourceEnums value() default DataSourceEnums.BUS_DATASOURCE_ID;
}
/**
* @author Lucky
* @date 2019-05-18
* <p>
* 开启动态数据源
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({DynamicDataSourceConfig.class})
public @interface EnableDynamicDataSource {
}
/**
* @author Lucky
* @date 2019-05-18
* <p>
* 自动配置类
*/
@AllArgsConstructor
@EnableConfigurationProperties({DruidDataSourceProperties.class})
public class DataSourceAutoConfiguration {
@Bean
public DataSourceAspect dataSourceAspect() {
return new DataSourceAspect();
}
}
3. Table Structure
Note that under this code, stringEncryptor.encrypt ( "Password") to use the database
4.yml
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
druid:
url: jdbc:mysql://123:3306/123?useUnicode=true&characterEncoding=utf-8&useServerPstmts=true&cachePrepStmts=true&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&cacheCallableStmts=true&connectTimeout=1000&maxReconnects=5&zeroDateTimeBehavior=convertToNull&useSSL=true
username: 123
password: 123
# 初始连接数
initialSize: 10
# 最大连接池数量
maxActive: 50
# 最小连接池数量
minIdle: 10
# 配置获取连接等待超时的时间
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
url-pattern: ${adminPath}/sys/druid/*
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
5. Use
1. annotations on application startup items of written springboot
2. Where you want to switch data sources together, here to pay attention to the next, a transaction can only support a data source, and transaction propagation behavior
Propagation.REQUIRES_NEW集合使用
5. achieve results:
If you perform this method appears logs, notes and handover success!