动态数据源的简单配置使用

使用场景

主要在多租户场景中,常常新的一个租户进来需要动态的添加一个数据源到库中,使得系统不用重启即可切换数据源。

如何实现

引入相关依赖,版本用最新的就行,注意引入 parent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  <!--   版本管理,由spring-boot统一整合管理版本   -->
<parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.7.0</version>
      <relativePath/>
  </parent>
  <dependencies>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
      </dependency>

      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>${druid-version}</version>
      </dependency>
      <!--   重点是这个包,这里有个天坑,2.x版本手动排除依赖不行!!建议使用parent标签    -->
      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>${dynamic-datasource-version}</version>
      </dependency>

      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>${mybatis-plus-version}</version>
      </dependency>
  </dependencies>

多数据源配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      lazy: true #默认false非懒启动,系统加载到数据源立即初始化连接池
      datasource:
        master:
          url: jdbc:mysql://192.168.10.46:3306/xxx?useUnicode=true&characterEncoding=utf-8
          username: xxx
          password: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave_1:
          url: jdbc:mysql://192.168.10.46:3306/xxx?useUnicode=true&characterEncoding=utf-8
          username: xxx
          password: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave_2:
          url: jdbc:mysql://192.168.10.46:3306/xxx?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
          username: xxx
          password: xxx
          driver-class-name: com.mysql.cj.jdbc.Driver

常规的多数据源配置方式如上所示,原理大致是每次启动时,将这些配置加载到某个地方进行管理,而要实现动态数据源,就需要直接操作,将数据源放入到这个个地方。因此,dynamic-datasource 提供了这么一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface DataSourceCreator {

    /**
     * 通过属性创建数据源
     *
     * @param dataSourceProperty 数据源属性
     * @return 被创建的数据源
     */
    DataSource createDataSource(DataSourceProperty dataSourceProperty);

    /**
     * 当前创建器是否支持根据此属性创建
     *
     * @param dataSourceProperty 数据源属性
     * @return 是否支持
     */
    boolean support(DataSourceProperty dataSourceProperty);
}

而由于接入方式的不同,会有不同的实现类,这些实现类都在 creator 包下

image-20220714161455298

我们来看两个常用的实现类

  • DruidDataSourceCreator:适配了 Druid 数据源
  • DefaultDataSourceCreator:这是一个通用的创建器,其根据环境自动选择连接池,默认的顺序为 druid>hikaricp>beecp>dbcp>spring basic

动态数据源使用

添加数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  @Autowired
  private DataSource dataSource;
  @Autowired
  private DefaultDataSourceCreator dataSourceCreator;

private void cacheAddSourceDTO(DataSourceDTO dto) {
      DataSourceProperty dataSourceProperty = new DataSourceProperty();
      // 添加至缓存
      BeanUtils.copyProperties(dto, dataSourceProperty);
      DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
      // 默认的顺序为druid>hikaricp>beecp>dbcp>spring basic
      DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
      ds.addDataSource(dto.getPoolName(), dataSource);
  }

删除数据源

1
2
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.removeDataSource(poolName);

源码解析

动态添加数据源的源码比较简单,一句话概括来说就是添加数据源的配置!下面是 druid 的实现

image-20220714163757757

可以看到对外暴露了三个方法,主要关注 doCreateDataSource 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public DataSource doCreateDataSource(DataSourceProperty dataSourceProperty) {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setUsername(dataSourceProperty.getUsername());
    dataSource.setPassword(dataSourceProperty.getPassword());
    dataSource.setUrl(dataSourceProperty.getUrl());
    dataSource.setName(dataSourceProperty.getPoolName());
    String driverClassName = dataSourceProperty.getDriverClassName();
    if (!StringUtils.isEmpty(driverClassName)) {
        dataSource.setDriverClassName(driverClassName);
    }
    DruidConfig config = dataSourceProperty.getDruid();
    Properties properties = config.toProperties(gConfig);

    List<Filter> proxyFilters = this.initFilters(dataSourceProperty, properties.getProperty("druid.filters"));
    dataSource.setProxyFilters(proxyFilters);

    dataSource.configFromPropety(properties);
    //连接参数单独设置
    dataSource.setConnectProperties(config.getConnectionProperties());
    //设置druid内置properties不支持的的参数
    this.setParam(dataSource, config);

    if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {
        try {
            dataSource.init();
        } catch (SQLException e) {
            throw new ErrorCreateDataSourceException("druid create error", e);
        }
    }
    return dataSource;
}

不难看出,返回类型为 DataSource,是 jdk 中 javax.sql 包提供的,用来连接数据库的实现。而前面所有的操作都是用来封装成 DataSource 这个对象的。

在实际使用过程中,有这么一行代码 (DynamicRoutingDataSource) dataSource,不难猜出,这里是管理所有数据源的地方,操作了这里才能实现动态添加。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Spring Boot可以配置动态数据源动态数据源是指在使用之前是不确定的或者不存在的数据源。在Spring Boot中,可以使用数据源或者仅有一个数据源来实现动态数据源。多数据源是指在Spring Boot上下文中可以配置多个DataSource,通过Spring容器的注入来指定。而动态数据源只有一个动态数据源对象,它可以根据使用要求动态修改连接信息,创建新的连接,并自动关闭旧的连接,实现数据源的自动切换。在Spring Boot 2.x版本之后,默认的数据源由原来的org.apache.tomcat.jdbc.pool.DataSource改为了com.zaxxer.hikari.HikariDataSource。HikariDataSource是一个速度很快的数据源,同时也是一个数据库连接池。通过封装数据源连接信息,可以使用HikariDataSource来创建动态数据源。具体的配置方法可以参考以下代码示例: ``` @Bean public DynamicDataSource customDataSource(DataSourceInfo dbInfo) throws SQLException, ClassNotFoundException { // 封装数据源连接信息 DataSourceProperties properties = new DataSourceProperties(); properties.setUrl(dbInfo.getJdbcUrl()); properties.setDriverClassName(dbInfo.getDriverClass()); properties.setUsername(dbInfo.getUserName()); properties.setPassword(dbInfo.getPassword()); // 使用HikariDataSource创建数据源 HikariDataSource hikariDataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); // 刷新数据源 dataSourceRefresher.refreshDataSource(hikariDataSource); return dynamicDataSource; } ``` 以上是配置动态数据源简单示例,通过封装数据源连接信息,使用HikariDataSource创建数据源,并通过refreshDataSource方法刷新数据源,实现动态数据源配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring Boot使用动态数据源](https://blog.csdn.net/qq_33594592/article/details/126702593)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

day day day ...

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值