赞
踩
目录
Spring Boot集成Druid实现多数据源的两种方式:
1、集成com.baomidou,引入dynamic-datasource依赖;
2、原生的方式,基于AOP手动实现多数据源;
1、maven依赖:- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
- <version>3.5.1</version>
- </dependency>
-
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.10</version>
- </dependency>
1.spring.datasource.dynamic前缀,是baomidou源码里固定的;
2.first、second是自定义的名称,可以更改;
- # 多数据源配置,默认master
- spring.datasource.dynamic.primary = first
- # 数据源1
- spring.datasource.dynamic.datasource.first.driverClassName = com.mysql.cj.jdbc.Driver
- spring.datasource.dynamic.datasource.first.type = com.alibaba.druid.pool.DruidDataSource
- spring.datasource.dynamic.datasource.first.url = jdbc:mysql://127.0.0.1:3306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.dynamic.datasource.first.username = test
- spring.datasource.dynamic.datasource.first.password = test1
- # 数据源2
- spring.datasource.dynamic.datasource.second.driverClassName = com.mysql.cj.jdbc.Driver
- spring.datasource.dynamic.datasource.second.type = com.alibaba.druid.pool.DruidDataSource
- spring.datasource.dynamic.datasource.second.url = jdbc:mysql://127.0.0.1:18306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.dynamic.datasource.second.username = test
- spring.datasource.dynamic.datasource.second.password = test1
-
- # druid多数据源全局配置
- spring.datasource.dynamic.druid.filter.stat.log-slow-sql = true
- spring.datasource.dynamic.druid.filter.stat.slow-sql-millis = 1000
- spring.datasource.dynamic.druid.min-evictable-idle-time-millis = 300000
- spring.datasource.dynamic.druid.test-on-borrow = false
- spring.datasource.dynamic.druid.filter.stat.merge-sql = false
- spring.datasource.dynamic.druid.test-on-return = false
- spring.datasource.dynamic.druid.initial-size = 10
- spring.datasource.dynamic.druid.min-idle = 10
- spring.datasource.dynamic.druid.max-wait = 60000
- spring.datasource.dynamic.druid.pool-prepared-statements = true
- spring.datasource.dynamic.druid.test-while-idle = true
- spring.datasource.dynamic.druid.validation-query = select 1
- spring.datasource.dynamic.druid.filter.wall.config.multi-statement-allow = true
- spring.datasource.dynamic.druid.time-between-eviction-runs-millis = 60000
- spring.datasource.dynamic.druid.max-pool-prepared-statement-per-connection-size = 20
- spring.datasource.dynamic.druid.max-active = 100
- # druid监控全局配置
- spring.datasource.druid.stat-view-servlet.enabled = true
- spring.datasource.druid.stat-view-servlet.url-pattern = /druid/*

验证配置文件是否生效:Spring Boot集成Druid查看配置是否生效_涛哥是个大帅比的博客-CSDN博客
@DS注解说明:
1.注解在方法上、类上、接口、枚举,同时存在就近原则,方法上注解优先于类上注解;
2.不使用@DS注解,默认主数据源;
类上:
- @DS("db2")
- public class test(){}
方法上:
- @DS("db2")
- public void test(){}
mapper方法上
- @Select("SELECT * FROM TEST WHERE A = #{A}")
- @DS("db2")
- Map<String, Object> test(@Param("A") String A);
多数据源可能会碰到事务问题:
Spring Boot多数据源事务@DSTransactional的使用_涛哥是个大帅比的博客-CSDN博客
1、maven依赖:- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.10</version>
- </dependency>
1.Spring Boot 2.X 版本不再支持配置继承,多数据源的话每个数据源的所有配置都需要单独配置,否则配置不会生效;
2.first、second是自定义的名称,对应DynamicDataSourceConfig配置类,可以更改;
- # 多数据源配置
- spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
- # 数据源1
- spring.datasource.druid.first.name = first
- spring.datasource.druid.first.driverClassName = com.mysql.cj.jdbc.Driver
- spring.datasource.druid.first.url = jdbc:mysql://127.0.0.1:3306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.druid.first.username = test
- spring.datasource.druid.first.password = test1
- # 数据源2
- spring.datasource.druid.second.name = second
- spring.datasource.druid.second.driverClassName = com.mysql.cj.jdbc.Driver
- spring.datasource.druid.second.url = jdbc:mysql://127.0.0.1:18306/mp_dm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
- spring.datasource.druid.second.username = test
- spring.datasource.druid.second.password = test1
-
- # druid数据源1
- spring.datasource.druid.first.filter.stat.log-slow-sql = true
- spring.datasource.druid.first.filter.stat.slow-sql-millis = 1000
- spring.datasource.druid.first.min-evictable-idle-time-millis = 300000
- spring.datasource.druid.test-on-borrow = false
- spring.datasource.druid.first.filter.stat.merge-sql = false
- spring.datasource.druid.test-on-return = false
- spring.datasource.druid.first.initial-size = 10
- spring.datasource.druid.first.min-idle = 10
- spring.datasource.druid.first.max-wait = 60000
- spring.datasource.druid.first.pool-prepared-statements = true
- spring.datasource.druid.first.test-while-idle = true
- spring.datasource.druid.first.validation-query = select 1
- spring.datasource.druid.first.filter.wall.config.multi-statement-allow = true
- spring.datasource.druid.first.time-between-eviction-runs-millis = 60000
- spring.datasource.druid.first.max-pool-prepared-statement-per-connection-size = 20
- spring.datasource.druid.first.max-active = 100
- # druid数据源2
- spring.datasource.druid.second.filter.stat.log-slow-sql = true
- spring.datasource.druid.second.filter.stat.slow-sql-millis = 1000
- spring.datasource.druid.second.min-evictable-idle-time-millis = 300000
- spring.datasource.druid.second.test-on-borrow = false
- spring.datasource.druid.second.filter.stat.merge-sql = false
- spring.datasource.druid.second.test-on-return = false
- spring.datasource.druid.second.initial-size = 10
- spring.datasource.druid.second.min-idle = 10
- spring.datasource.druid.second.max-wait = 60000
- spring.datasource.druid.second.pool-prepared-statements = true
- spring.datasource.druid.second.test-while-idle = true
- spring.datasource.druid.second.validation-query = select 1
- spring.datasource.druid.second.filter.wall.config.multi-statement-allow = true
- spring.datasource.druid.second.time-between-eviction-runs-millis = 60000
- spring.datasource.druid.second.max-pool-prepared-statement-per-connection-size = 20
- spring.datasource.druid.second.max-active = 100
- # druid监控全局配置
- spring.datasource.druid.stat-view-servlet.enabled = true
- spring.datasource.druid.stat-view-servlet.url-pattern = /druid/*

验证配置文件是否生效:Spring Boot集成Druid查看配置是否生效_涛哥是个大帅比的博客-CSDN博客
- package com.test.datasources;
-
- /**
- * 增加多数据源,在此配置
- */
- public interface DataSourceNames {
- String FIRST = "first";
- String SECOND = "second";
-
- }
- package com.test.datasources.annotation;
-
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * 多数据源注解
- */
- //同时支持方法注解和类注解
- @Target({ElementType.METHOD, ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface DataSource {
- String value() default "";
- }

- package com.test.datasources;
-
- import java.util.HashMap;
- import java.util.Map;
-
- import javax.sql.DataSource;
-
- 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 org.springframework.jdbc.core.JdbcTemplate;
-
- import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
-
- /**
- * 配置多数据源
- */
- @Configuration
- public class DynamicDataSourceConfig {
-
- @Bean
- @ConfigurationProperties("spring.datasource.druid.first")
- public DataSource firstDataSource(){
- return DruidDataSourceBuilder.create().build();
- }
-
- @Bean
- @ConfigurationProperties("spring.datasource.druid.second")
- public DataSource secondDataSource(){
- return DruidDataSourceBuilder.create().build();
- }
-
- @Bean
- @Primary
- public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
- Map<Object, Object> targetDataSources = new HashMap<>();
- targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
- targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
- return new DynamicDataSource(firstDataSource, targetDataSources);
- }
-
- @Bean
- public JdbcTemplate jdbcTemplate() {
- return new JdbcTemplate(firstDataSource());
- }
- }

- package com.test.datasources;
-
- import java.util.Map;
-
- import javax.sql.DataSource;
-
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
-
- /**
- * 动态数据源,关键代码
- */
- public class DynamicDataSource extends AbstractRoutingDataSource {
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
-
- public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
- super.setDefaultTargetDataSource(defaultTargetDataSource);
- super.setTargetDataSources(targetDataSources);
- super.afterPropertiesSet();
- }
-
- @Override
- protected Object determineCurrentLookupKey() {
- return getDataSource();
- }
-
- public static void setDataSource(String dataSource) {
- contextHolder.set(dataSource);
- }
-
- public static String getDataSource() {
- return contextHolder.get();
- }
-
- public static void clearDataSource() {
- contextHolder.remove();
- }
-
- }

- package com.test.datasources.aspect;
-
- import java.lang.reflect.Method;
-
- 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.Ordered;
- import org.springframework.stereotype.Component;
-
- import com.test.datasources.DataSourceNames;
- import com.test.datasources.DynamicDataSource;
- import com.test.datasources.annotation.DataSource;
-
- /**
- * 多数据源,切面处理类
- */
- @Aspect
- @Component
- public class DataSourceAspect implements Ordered {
- protected Logger logger = LoggerFactory.getLogger(getClass());
-
- /*
- * @annotation匹配指定注解的方法
- * @within匹配指定注解的类
- * 注意:这里只拦截所注解的类,如果调用的是父类的方法,那么不会拦截,除非父类方法在子类中被覆盖。
- */
- @Pointcut("@annotation(com.test.datasources.annotation.DataSource) || @within(com.test.datasources.annotation.DataSource)")
- public void dataSourcePointCut() {
-
- }
-
- @Around("dataSourcePointCut()")
- public Object around(ProceedingJoinPoint point) throws Throwable {
- MethodSignature signature = (MethodSignature) point.getSignature();
- Method method = signature.getMethod();
- Class<?> dataClass = Class.forName(signature.getDeclaringTypeName());
-
- DataSource dsMethod = method.getAnnotation(DataSource.class);
- DataSource dsClass = dataClass.getAnnotation(DataSource.class);
- if(dsMethod != null){
- //方法优先,如果方法上存在注解,则优先使用方法上的注解
- DynamicDataSource.setDataSource(dsMethod.value());
- logger.debug("set datasource is " + dsMethod.value());
- }else if(dsClass != null){
- //其次类优先,如果类上存在注解,则使用类上的注解
- DynamicDataSource.setDataSource(dsClass.value());
- logger.debug("set datasource is " + dsClass.value());
- }else{
- //如果都不存在,则使用默认
- DynamicDataSource.setDataSource(DataSourceNames.FIRST);
- logger.debug("set datasource is " + DataSourceNames.FIRST);
- }
-
- try {
- return point.proceed();
- } finally {
- DynamicDataSource.clearDataSource();
- logger.debug("clean datasource");
- }
- }
-
- @Override
- public int getOrder() {
- return 1;
- }
- }

- package com.test.mapper;
-
- import org.apache.ibatis.annotations.Mapper;
- import org.apache.ibatis.annotations.Param;
- import org.apache.ibatis.annotations.Select;
-
- import com.test.entity.Test1Entity;
-
- @Mapper
- public interface Test1Dao {
-
- @Select("select * from test1")
- Test1Entity getById(@Param("id")Integer id);
- }
- package com.test.mapper;
-
- import org.apache.ibatis.annotations.Mapper;
- import org.apache.ibatis.annotations.Param;
- import org.apache.ibatis.annotations.Select;
-
- import com.test.entity.Test2Entity;
-
- @Mapper
- public interface Test2Dao {
- @Select("select * from test2")
- Test2Entity getById(@Param("id")Integer id);
- }
- package com.test.service;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import com.test.datasources.DataSourceNames;
- import com.test.datasources.annotation.DataSource;
- import com.test.entity.Test1Entity;
- import com.test.mapper.Test1Dao;
-
- @Service
- @DataSource(DataSourceNames.FIRST)
- public class Test1Service {
-
- @Autowired
- private Test1Dao test1Dao;
-
- public Test1Entity getById(int id) {
- return test1Dao.getById(id);
- }
- }

- package com.test.service;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- import com.test.datasources.DataSourceNames;
- import com.test.datasources.annotation.DataSource;
- import com.test.entity.Test2Entity;
- import com.test.mapper.Test2Dao;
-
- @Service
- @DataSource(DataSourceNames.SECOND)
- public class Test2Service {
-
- @Autowired
- private Test2Dao test2Dao;
-
- public Test2Entity getById(int id) {
- return test2Dao.getById(id);
- }
- }

- package com.test.controller;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
-
- import com.test.entity.Test1Entity;
- import com.test.entity.Test2Entity;
- import com.test.service.Test1Service;
- import com.test.service.Test2Service;
-
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
-
- /**
- * 动态数据源测试
- */
- @Api(tags = "动态数据源测试")
- @RestController
- @RequestMapping("/test")
- public class DynamicController {
-
- @Autowired
- private Test1Service test1Service;
- @Autowired
- private Test2Service test2Service;
-
- @ApiOperation(value = "数据源1")
- @RequestMapping(value = "/test1", method = RequestMethod.GET)
- public String test1() {
- Test1Entity entity = test1Service.getById(1);
- return entity.getName();
- }
-
- @ApiOperation(value = "数据源2")
- @RequestMapping(value = "/test2", method = RequestMethod.GET)
- public String test2() {
- Test2Entity entity = test2Service.getById(2);
- return entity.getName();
- }
- }

多数据源可能会碰到事务问题:https://blog.csdn.net/u011974797/article/details/130154340
服务启动会打印日志:
- com.alibaba.druid.pool.DruidDataSource : {dataSource-1,first} inited
- com.alibaba.druid.pool.DruidDataSource : {dataSource-2,second} inited
druid监控页面:


Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。