Springboot配置mysql数据源+druid连接池,配置多数据源

Springboot配置mysql数据源+druid连接池,支持多数据源

一、配置mysql+druid

1、导入数据源所需jar,此处只导入了必要的,其他工具自行配置

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

2、配置yml,若只需要配置单数据源,自行删除相关数据库配置即可。

spring:
  # jackson
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

  #多数据源需要配置
  main:
    allow-bean-definition-overriding: true
  # druid数据源配置
  datasource:
    name: druidDataSource
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      first:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://ip:port/db_name?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
        username: username
        password: password
      second:
         url: jdbc:mysql://ip:port/db_name?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
        username: username
        password: password
      third:
         url: jdbc:mysql://ip:port/db_name?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
        username: username
        password: password


      filters: stat,wall,config
      max-active: 100
      initial-size: 1
      max-wait: 60000
      min-idle: 1
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: select 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 50
      max-pool-prepared-statement-per-connection-size: 20
      web-stat-filter:
        # 添加过滤规则
        url-pattern: /*
        # 忽略过滤格式
        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
      stat-view-servlet:
        # 设置ip白名单
        allow: 127.0.0.1
        # 设置ip黑名单,优先级高于白名单
        deny:
        # 设置控制台管理用户
        #        login-username: root
        #        login-password: root
        # 是否可以重置数据
        reset-enable: false
        # 开启druid监控页面
        enabled: true

二、配置多数据源

1、配置多数据源名称的枚举接口,方便管理

/**
 * @ClassName : DataSourceConfig
 * @Description : 多数据源名称
 * @Author : Jinwei
 * @Date: 2020-05-29 09:59
 */
public interface DataSourceNames {

    String FIRST = "first";
    String SECOND = "second";
    String THIRD = "third";

}

2、配置注解,在使用数据源时,直接在需要的配置的方法上面加上数据源注解即可。

/**
 * @ClassName : DataSource
 * @Description : 多数据源注解
 * @Author : Jinwei
 * @Date: 2020-05-29 10:12
 */

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

3、配置多数据源实例

/**
 * @ClassName : DynamicDataSourceConfig
 * @Description : 多数据源配置
 * @Author : Jinwei
 * @Date: 2020-05-29 10:20
 */
@Configuration
public class DynamicDataSourceConfig {
    //对应yml文件中的数据源名称
    @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
    @ConfigurationProperties("spring.datasource.druid.third")
    public DataSource thirdDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    //对应yml文件中的数据源名称,以及枚举类中的名称
    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource, DataSource thirdDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
        targetDataSources.put(DataSourceNames.THIRD, thirdDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
}

4、配置动态数据源

/**
 * @ClassName : DynamicDataSource
 * @Description : 动态数据源
 * @Author : Jinwei
 * @Date: 2020-05-29 10:22
 */
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();
    }

}

5、配置多数据源切面处理


/**
 * @ClassName : DataSourceAspect
 * @Description : 多数据源切面处理类
 * @Author : Jinwei
 * @Date: 2020-05-29 10:25
 */
@Aspect
@Component
public class DataSourceAspect {
    
    @Pointcut("@annotation(com.kalvin.kvf.modules.zax.common.dateSourceConfig.DataSource) " +
            "|| @within(com.kalvin.kvf.modules.zax.common.dateSourceConfig.DataSource)")
    public void dataSourcePointCut() {

    }

    //此处可以获取到类和方法上面的注解,大多数情况下,只需要使用类上面的,或者方法上面的。可以自行删减一个。
    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获得类上的数据源注解
        Class clazz = point.getSignature().getDeclaringType();
        DataSource dataClass = (DataSource) clazz.getAnnotation(DataSource.class);
        //获得方法上的数据源注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource dsMethod = method.getAnnotation(DataSource.class);

        if (dataClass != null) {
            dsMethod = dataClass;
        }

        if (dsMethod == null) {
            DynamicDataSource.setDataSource(DataSourceNames.FIRST);
            logger.debug("set datasource is " + DataSourceNames.FIRST);
        } else {
            DynamicDataSource.setDataSource(dsMethod.name());
            logger.debug("set datasource is " + dsMethod.name());
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

}

三、使用多数据源、增加多数据源

1、使用多数据源

只需要在你所需要使用多数据源的数据访问层(即service)层,对应的实现类上面,或者实现类中对应的方法上面,增加注解:

@DataSource(name = DataSourceNames.FIRST)
@DataSource(name = DataSourceNames.SECOND)
@DataSource(name = DataSourceNames.THIRD)

2、增加多数据源

增加多数据源,按照次流程,依次在yml文件、数据源名称枚举类、多数据源实例类,增加对应的代码。使用时与其他的一样,都是添加注解。

四、问题解决

1、多数据源切面无法进入

方案:在切面上,添加注解:

   @Pointcut("@annotation(com.kalvin.kvf.modules.zax.common.dateSourceConfig.DataSource) " +
            "|| @within(com.kalvin.kvf.modules.zax.common.dateSourceConfig.DataSource)")
    public void dataSourcePointCut() {

    }

2、多数据源在service中,或是在循环中,只生效一次。

剖析:测试中发现,如果在service方法上添加数据源,在方法内写循环,写mapper,此时可能出现指定数据源只出现一次的情况。

方案:需要写一个公共的service,此service专用于查询mapper,每个mapper一个方法,每个方法一个注解。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,你的问题是关于如何在Spring Boot应用中实现多数据源动态切换,使用的技术包括Spring Boot、MyBatis、MySQL、Oracle、Druid数据源连接池、自定义注解和切面,并且配置文件使用application.yml格式。 首先,需要在pom.xml文件中添加相应的依赖: ```xml <!--Spring Boot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--MyBatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!--MySQL--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> <!--Oracle--> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>19.3.0.0</version> </dependency> <!--Druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> ``` 接下来,需要在application.yml文件中配置数据源和MyBatis相关的属性,例如: ```yaml spring: datasource: druid: # 数据源1 db1: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root # 数据源2 db2: driver-class-name: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: scott password: tiger # 默认数据源 url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity ``` 然后,需要定义一个自定义注解,用于标识哪些方法需要使用哪个数据源: ```java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String value() default "db1"; } ``` 在数据源切换的时候,我们需要获取注解上指定的数据源名称,因此需要定义一个切面: ```java @Aspect @Component public class DataSourceAspect { @Around("@annotation(ds)") public Object around(ProceedingJoinPoint point, DataSource ds) throws Throwable { String dataSourceName = ds.value(); DynamicDataSource.setDataSource(dataSourceName); try { return point.proceed(); } finally { DynamicDataSource.clearDataSource(); } } } ``` 最后,需要定义一个动态数据源,用于实现数据源的切换: ```java public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<>(); @Override protected Object determineCurrentLookupKey() { return dataSourceHolder.get(); } public static void setDataSource(String dataSourceName) { dataSourceHolder.set(dataSourceName); } public static void clearDataSource() { dataSourceHolder.remove(); } } ``` 至此,多数据源动态切换的配置就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CloverAn

如果文章对你有帮助,感谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值