本文章与上篇文章对应,在上篇文章的基础上增加数据源,连接池与上篇文章一致

1.HikariCP 多数据源

1.1引入依赖

无需主动引入 HikariCP 的依赖。因为在 Spring Boot 2.X 中,spring-boot-starter-jdbc 默认引入 com.zaxxer.HikariCP 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>
 
    <artifactId>lab-19-datasource-pool-hikaricp-single</artifactId>
 
    <dependencies>
        <!-- 实现对数据库连接池的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency> 
        <!-- 本示例,我们使用 MySQL -->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <!-- 方便写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

1.2应用配置文件

在 application.yml 中,添加 HikariCP 配置,如下:

spring:
  # datasource 数据源配置内容
  datasource:
    # 订单数据源配置
    orders:
      url: jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password:
      # HikariCP 自定义配置,对应 HikariConfig 配置属性类
      hikari:
        minimum-idle: 20 # 池中维护的最小空闲连接数,默认为 10 个。
        maximum-pool-size: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。
    # 用户数据源配置
    users:
      url: jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password:
      # HikariCP 自定义配置,对应 HikariConfig 配置属性类
      hikari:
        minimum-idle: 15 # 池中维护的最小空闲连接数,默认为 10 个。
        maximum-pool-size: 15 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。

我们在 spring.datasource 配置项下,定义了 orders 和 users 两个数据源的配置。而每个数据源的配置,和我们单数据源配置是一致的。

1.3数据源配置类

1.3.1错误示例

在网上,我们会看到这样配置多个数据源的配置类。代码如下:

@Bean(name = "ordersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.orders")
public DataSource ordersDataSource() {
   return DataSourceBuilder.create().build();
}

@Bean(name = "usersDataSource")
@ConfigurationProperties(prefix = "spring.datasource.users")
public DataSource ordersDataSource() {
   return DataSourceBuilder.create().build();
}

实际上,这样做的话,在部分场景下,会存在问题,这是为什么呢?我们先来理解这段程序的用途。以 #ordersDataSource() 方法为例子:

  • DataSourceBuilder.create().build() 代码段,会创建一个 DataSource 数据源。
  • 搭配上 @Bean(name = “ordersDataSource”) 注解,会创建一个名字为 “ordersDataSource” 的 DataSource Bean 。这里,我们使用 HikariCP ,所以返回的是 HikariDataSource Bean 。
  • @ConfigurationProperties(prefix = “spring.datasource.orders”) 注解,会将 “spring.datasource.orders” 配置项,逐个属性赋值给 DataSource Bean 。
  • 看起来貌似没问题,但是如果每个数据源如果有 HikariCP 的 “hikari” 自定义配置项时,它的自定义配置项无法设置到 HikariDataSource Bean 中。因为,“spring.datasource.orders.hikari” 是 “spring.datasource.orders” 的第二层属性。而 HikariDataSource 的配置属性在第一层,这就导致无法正确的设置。

虽然存在该问题,但是大多数项目,我们并不会自定义 HikariCP 的 “hikari” 配置项,所以这个问题就偷偷藏起来,**“不存在”**了。

1.3.2 正确的示例

当然,作为入门的示例,艿艿还是希望提供正确的做法。
在 cn.iocoder.springboot.lab19.datasourcepool.config 包路径下,我们会创建 DataSourceConfig 配置类。代码如下:

// DataSourceConfig.java

@Configuration
public class DataSourceConfig {

    /**
     * 创建 orders 数据源的配置对象
     */
    @Primary
    @Bean(name = "ordersDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 DataSourceProperties 对象
    public DataSourceProperties ordersDataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 创建 orders 数据源
     */
    @Bean(name = "ordersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.orders.hikari") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
    public DataSource ordersDataSource() {
        // <1.1> 获得 DataSourceProperties 对象
        DataSourceProperties properties =  this.ordersDataSourceProperties();
        // <1.2> 创建 HikariDataSource 对象
        return createHikariDataSource(properties);
    }

    /**
     * 创建 users 数据源的配置对象
     */
    @Bean(name = "usersDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.users") // 读取 spring.datasource.users 配置到 DataSourceProperties 对象
    public DataSourceProperties usersDataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 创建 users 数据源
     */
    @Bean(name = "usersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.users.hikari")
    public DataSource usersDataSource() {
        // 获得 DataSourceProperties 对象
        DataSourceProperties properties =  this.usersDataSourceProperties();
        // 创建 HikariDataSource 对象
        return createHikariDataSource(properties);
    }

    private static HikariDataSource createHikariDataSource(DataSourceProperties properties) {
        // 创建 HikariDataSource 对象
        HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
        // 设置线程池名
        if (StringUtils.hasText(properties.getName())) {
            dataSource.setPoolName(properties.getName());
        }
        return dataSource;
    }

}
  • 这块代码,我们是参考 Spring Boot DataSourceConfiguration.Hikari 配置类来实现的。
  • #ordersDataSourceProperties() 方法,创建 “orders” 数据源的 DataSourceProperties 配置对象。
  • @Primary 注解,保证项目中有一个主的 DataSourceProperties Bean 。
  • new DataSourceProperties() 代码段,会创建一个 DataSourceProperties 数据源的配置对象。搭配上 @Bean(name = “ordersDataSourceProperties”) 注解,会创建一个名字为 “ordersDataSourceProperties” 的 DataSourceProperties Bean 。
  • @ConfigurationProperties(prefix = “spring.datasource.orders”) 注解,会将 “spring.datasource.orders” 配置项,逐个属性赋值给 DataSourceProperties Bean 。
  • #ordersDataSource() 方法,创建 orders 数据源。
  • <1.1> 处,调用 #ordersDataSourceProperties() 方法,获得 orders 数据源的 DataSourceProperties 。
  • <1.2> 处,调用 #createHikariDataSource(DataSourceProperties properties) 方法,创建 HikariDataSource 对象。这样,“spring.datasource.orders” 配置项,逐个属性赋值给 HikariDataSource Bean 。
  • 搭配上 @Bean(name = “ordersDataSource”) 注解,会创建一个名字为 “ordersDataSource” 的 HikariDataSource Bean 。
  • @ConfigurationProperties(prefix = “spring.datasource.orders.hikari”) 注解,会将 HikariCP 的 “spring.datasource.orders.hikari” 自定义配置项,逐个属性赋值给 HikariDataSource Bean 。

users 数据源的配置,同上,就不重复解释了。

1.4 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java
@SpringBootApplication
public class Application implements CommandLineRunner {

    private Logger logger = LoggerFactory.getLogger(Application.class);

    @Resource(name = "ordersDataSource")
    private DataSource ordersDataSource;

    @Resource(name = "usersDataSource")
    private DataSource usersDataSource;

    public static void main(String[] args) {
        // 启动 Spring Boot 应用
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) {
        // orders 数据源
        try (Connection conn = ordersDataSource.getConnection()) {
            // 这里,可以做点什么
            logger.info("[run][ordersDataSource 获得连接:{}]", conn);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        // users 数据源
        try (Connection conn = usersDataSource.getConnection()) {
            // 这里,可以做点什么
            logger.info("[run][usersDataSource 获得连接:{}]", conn);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

}

执行日志如下

2022-08-25 15:30:35.060  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-08-25 15:30:35.365  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2022-08-25 15:30:35.367  INFO 45868 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][ordersDataSource 获得连接:HikariProxyConnection@1041547629 wrapping com.mysql.jdbc.JDBC4Connection@3c989952]
2022-08-25 15:30:35.371  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2022-08-25 15:30:35.376  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
2022-08-25 15:30:35.376  INFO 45868 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][usersDataSource 获得连接:HikariProxyConnection@795748540 wrapping com.mysql.jdbc.JDBC4Connection@7c098bb3]

可以看到两个数据源初始化成功了

2.Druid 多数据源

2.1引入依赖

 <dependencies>
        <!-- 保证 Spring JDBC 的依赖健全 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 实现对 Druid 连接池的自动化配置 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency> <!-- 本示例,我们使用 MySQL -->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
 
        <!-- 实现对 Spring MVC 的自动化配置,因为我们需要看看 Druid 的监控功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <!-- 方便写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.2应用配置

在 application.yml 中,添加 Druid 配置,如下:

spring:
  # datasource 数据源配置内容
  datasource:
    # 订单数据源配置
    orders:
      url: jdbc:mysql://127.0.0.1:3306/test_orders?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: 123456
      type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
      # Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
      min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
      max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
    # 用户数据源配置
    users:
      url: jdbc:mysql://127.0.0.1:3306/test_users?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      driver-class-name: com.mysql.jdbc.Driver
      username: root
      password: 123456
      type: com.alibaba.druid.pool.DruidDataSource # 设置类型为 DruidDataSource
      # Druid 自定义配置,对应 DruidDataSource 中的 setting 方法的属性
      min-idle: 0 # 池中维护的最小空闲连接数,默认为 0 个。
      max-active: 20 # 池中最大连接数,包括闲置和使用中的连接,默认为 8 个。
    # Druid 自定已配置
    druid:
      # 过滤器配置
      filter:
        stat: # 配置 StatFilter ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
          log-slow-sql: true # 开启慢查询记录
          slow-sql-millis: 5000 # 慢 SQL 的标准,单位:毫秒
      # StatViewServlet 配置
      stat-view-servlet: # 配置 StatViewServlet ,对应文档 https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
        enabled: true # 是否开启 StatViewServlet
        login-username: admin # 账号
        login-password: admin # 密码

2.3数据源配置类

在 cn.iocoder.springboot.lab19.datasourcepool.config 包路径下,我们会创建 DataSourceConfig 配置类。代码如下:

// DataSourceConfig.java
@Configuration
public class DataSourceConfig {
    /**
     * 创建 orders 数据源
     */
    @Primary
    @Bean(name = "ordersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
    public DataSource ordersDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 创建 users 数据源
     */
    @Bean(name = "usersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.users")
    public DataSource usersDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
    
}

因为我们在 「2.2 应用配置」 中,将 Druid 自定义的配置项,和数据源的通用配置放在了同一级,所以我们只需使用 @ConfigurationProperties(prefix = “spring.datasource.orders”) 这样的方式即可。
当然,「1.3.2 正确的示例」 也是可以这么做的。实际情况下,比较推荐本小节的方式。

2.4 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java
@SpringBootApplication
public class Application implements CommandLineRunner {

    private Logger logger = LoggerFactory.getLogger(Application.class);

    @Resource(name = "ordersDataSource")
    private DataSource ordersDataSource;

    @Resource(name = "usersDataSource")
    private DataSource usersDataSource;

    public static void main(String[] args) {
        // 启动 Spring Boot 应用
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) {
        // orders 数据源
        logger.info("[run][获得数据源:{}]", ordersDataSource.getClass());

        // users 数据源
        logger.info("[run][获得数据源:{}]", usersDataSource.getClass());
    }

}

执行日志如下:

2022-08-25 21:39:24.063  INFO 49670 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][获得数据源:class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]
2022-08-25 21:39:24.064  INFO 49670 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][获得数据源:class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper]

可以看到,两个 DruidDataSource 成功初始化。

2.5监控功能

与单数据源一样,不过这个可以看到两个数据源

摘要: 原创出处[芋道源码]