目录
一、配置流程
二、YML配置文件
三、Druid配置类详情,可拆分对应配置
四、涉及工具类(注解、切面、枚举、保存当前线程的数据源类型)
五、参考文档地址
1、yml增加配置数据源配置信息;
2、配置对应数据源的DataSource对象;
3、配置对应的AbstractRoutingDataSource对象信息;
4、配置SqlSessionFactory配置信息,需要将路由配置信息配置于对应的SqlSession中;
5、配置对应的数据源事务管理器;
6、方法上增加注解,切换数据源。
spring:
#数据库配置
datasource:
username: ****
password: ****
url: jdbc:mysql://****:3306/database_master?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#druid 数据源专有配置
druid:
#初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
initial-size: 20
#最小连接池数量
min-idle: 20
#最大连接池数量
max-active: 80
#获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
max-wait: 60000
#有两个含义: 1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
timeBetweenEvictionRunsMillis: 60000
#连接保持空闲⽽而不不被驱逐的最⻓长时间
minEvictableIdleTimeMillis: 300000
# 校验SQL,Oracle配置 spring.datasource.validationQuery=SELECT 1 FROM DUAL,如果不配validationQuery项,则下面三项配置无用
validation-query: SELECT 'X'
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
mysql-salve:
username: ****
password: ****
url: jdbc:mysql://****:3306/database_slave?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver;
import com.yswl.smart.tool.aspect.EnumDataSourceType;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
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.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* 类文件描述:DruidConfig
*
* @date 2022/02/22 10:31
*/
@Configuration
@Slf4j
public class DruidConfig {
@Value("${spring.datasource.url}")
private String masterDbUrl;
@Value("${spring.datasource.username}")
private String masterUsername;
@Value("${spring.datasource.password}")
private String masterPassword;
@Value("${spring.datasource.driver-class-name}")
private String masterDriverClassName;
@Value("${spring.datasource.mysql-slave.url}")
private String slaveDbUrl;
@Value("${spring.datasource.mysql-slave.username}")
private String slaveUsername;
@Value("${spring.datasource.mysql-slave.password}")
private String slavePassword;
@Value("${spring.datasource.mysql-slave.driver-class-name}")
private String slaveDriverClassName;
@Value("${spring.datasource.druid.initial-size}")
private int initialSize;
@Value("${spring.datasource.druid.min-idle}")
private int minIdle;
@Value("${spring.datasource.druid.max-active}")
private int maxActive;
@Value("${spring.datasource.druid.max-wait}")
private int maxWait;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validation-query}")
private String validationQuery;
@Value("${spring.datasource.druid.test-while-idle}")
private boolean testWhileIdle;
@Value("${spring.datasource.druid.test-on-borrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.druid.test-on-return}")
private boolean testOnReturn;
@Value("${spring.datasource.druid.pool-prepared-statements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.druid.max-pool-prepared-statement-per-connection-size}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.druid.filters}")
private String filters;
@Value("${spring.datasource.druid.connection-properties}")
private String connectionProperties;
@Value("${spring.datasource.druid.use-global-data-source-stat}")
private boolean useGlobalDataSourceStat;
@Bean
@Primary
public DataSource masterDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.masterDbUrl);
datasource.setUsername(this.masterUsername);
datasource.setPassword(this.masterPassword);
datasource.setDriverClassName(this.masterDriverClassName);
return this.creatDataSource(datasource);
}
@Bean(name = "slaveDataSource")
public DataSource slaveOneDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.slaveDbUrl);
datasource.setUsername(this.slaveUsername);
datasource.setPassword(this.slavePassword);
datasource.setDriverClassName(this.slaveDriverClassName);
return this.creatDataSource(datasource);
}
@Bean
public AbstractRoutingDataSource routingDataSource() {
Map
import java.lang.annotation.*;
/**
* 类文件描述:数据源切换注解类,默认主数据源
*
* @date 2022/02/22 14:00
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DBType {
EnumDataSourceType value() default EnumDataSourceType.MYSQL_MASTER;
}
import com.yswl.smart.tool.annotation.DBType;
import com.yswl.smart.tool.config.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
/**
* 类文件描述: 数据源切换AOP切面
*
* @date 2022/02/22 14:00
*/
@EnableAspectJAutoProxy
@Aspect
@Component
@Slf4j
public class DataSourceAspect {
/**
* 方法描述:注解标识方法执行前 @annotation中需要替换为自己对应的注解全路径
*
* @param joinPoint joinPoint
* @date 2022/2/22 16:16
*/
@Before("@annotation(com.tool.annotation.DBType)")
public void before(JoinPoint joinPoint) {
// 获取连接点签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
DBType annotation = signature.getMethod().getAnnotation(DBType.class);
String databaseType = annotation.value().getValue();
DataSourceContextHolder.setDataSourceType(databaseType);
}
@After("@annotation(com.tool.annotation.DBType)")
public void afterMaster() {
DataSourceContextHolder.clear();
}
}
/**
* 类文件描述:数据源枚举
*
* @date 2022/2/22 15:09
*/
public enum EnumDataSourceType {
MYSQL_MASTER("master"),
MYSQL_SLAVE("salve");
/**
* 参数类型
*/
private String value;
EnumDataSourceType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
import lombok.experimental.UtilityClass;
/**
* 类文件描述:保存当前线程的数据源类型
*
* @date 2022/02/22 15:31
*/
@UtilityClass
public class DataSourceContextHolder {
private static final ThreadLocal LOCAL = new ThreadLocal<>();
public static ThreadLocal getLocal() {
return LOCAL;
}
public static void setDataSourceType(String dataSourceType) {
LOCAL.set(dataSourceType);
}
public static String getDataSourceRoutingKey() {
return LOCAL.get();
}
public static void clear() {
LOCAL.remove();
}
}
Spring Boot多数据源配置/读写分离(Druid+MyBatisPlus)_聚沙成塔-CSDN博客_springboot多数据源配置读写分离
springboot多数据源&动态数据源(主从) - xj-record - 博客园
Spring Boot多数据源配置实现读写分离_noralthank的博客-CSDN博客_springboot 多数据源 读写分离
Mybatis-Plus与Mybatis的sqlSessionFactory自定义 - 写代码其实苦的 - 博客园
AOP方法拦截获取参数上的注解 - 简书