切换注解、默认为主库
@Target({
ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{
/*** 切换数据源名称*/public DataSourceType value() default DataSourceType.MASTER;
}
动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource
{
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources){
super.setDefaultTargetDataSource(defaultTargetDataSource);super.setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected Object determineCurrentLookupKey(){
return DynamicDataSourceContextHolder.getDataSourceType();}
}
数据源切换处理
public class DynamicDataSourceContextHolder
{
public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/*** 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源的变量*/public static void setDataSourceType(String dsType){
log.info("切换到{}数据源", dsType);CONTEXT_HOLDER.set(dsType);}/*** 获得数据源的变量*/public static String getDataSourceType(){
return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void clearDataSourceType(){
CONTEXT_HOLDER.remove();}
}
属性配置
@Configuration
public class DruidProperties
{
@Value("${spring.datasource.druid.initialSize}")private int initialSize;@Value("${spring.datasource.druid.minIdle}")private int minIdle;@Value("${spring.datasource.druid.maxActive}")private int maxActive;@Value("${spring.datasource.druid.maxWait}")private int maxWait;@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")private int timeBetweenEvictionRunsMillis;@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")private int minEvictableIdleTimeMillis;@Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")private int maxEvictableIdleTimeMillis;@Value("${spring.datasource.druid.validationQuery}")private String validationQuery;@Value("${spring.datasource.druid.testWhileIdle}")private boolean testWhileIdle;@Value("${spring.datasource.druid.testOnBorrow}")private boolean testOnBorrow;@Value("${spring.datasource.druid.testOnReturn}")private boolean testOnReturn;public DruidDataSource dataSource(DruidDataSource datasource){
/** 配置初始化大小、最小、最大 */datasource.setInitialSize(initialSize);datasource.setMaxActive(maxActive);datasource.setMinIdle(minIdle);/** 配置获取连接等待超时的时间 */datasource.setMaxWait(maxWait);/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);/** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);/*** 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。*/datasource.setValidationQuery(validationQuery);/** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */datasource.setTestWhileIdle(testWhileIdle);/** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */datasource.setTestOnBorrow(testOnBorrow);/** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */datasource.setTestOnReturn(testOnReturn);return datasource;}
}
核心配置多数据源
@Configurationpublic class 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@ConfigurationProperties("spring.datasource.druid.devops")@ConditionalOnProperty(prefix = "spring.datasource.druid.devops", name = "enabled", havingValue = "true")public DataSource devOpsDataSource(){
return DruidDataSourceBuilder.create().build();}@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource, DataSource devOpsDataSource){
Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);targetDataSources.put(DataSourceType.DEVOPS.name(), devOpsDataSource);return new DynamicDataSource(masterDataSource, targetDataSources);}
yml配置
# 数据源配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverdruid:# 主库数据源master:url: jdbc:mysql://xxxx/crop_link?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: xxxxpassword: xxxx# 从库数据源slave:# 从数据源开关/默认关闭enabled: trueurl: jdbc:mysql://xxxxx/creditdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=trueusername: xxxpassword: xxx#运维用户数据库源devops:# 从数据源开关/默认关闭enabled: trueurl: jdbc:mysql://xxxx/mntdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=trueusername: xxxxpassword: xxxx# 初始连接数initialSize: 5# 最小连接池数量minIdle: 10# 最大连接池数量maxActive: 20# 配置获取连接等待超时的时间maxWait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一个连接在池中最小生存的时间,单位是毫秒minEvictableIdleTimeMillis: 300000# 配置一个连接在池中最大生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000# 配置检测连接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsewebStatFilter:enabled: truestatViewServlet:enabled: true# 设置白名单,不填则允许所有访问allow:url-pattern: /druid/*# 控制台管理用户名和密码login-username:login-password:filter:stat:enabled: true# 慢SQL记录log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true
枚举数据名称
public enum DataSourceType
{
/*** 主库*/MASTER,/*** 从库*/SLAVE,/*** 运维数据库*/DEVOPS
}
使用案例