Spring Boot HikariCP数据库连接池入门

35 篇文章 0 订阅
35 篇文章 0 订阅

1. 概述

在我们的项目中,数据库连接池基本是必不可少的组件。在目前数据库连接池的选型中,主要是

  • Druid,为监控而生的数据库连接池。
  • HikariCP,号称性能最好的数据库连接池。

至于怎么选择,两者都非常优秀,不用过多纠结。

  • Spring Boot 2.X 版本,默认采用 HikariCP 。
  • 阿里大规模采用 Druid 。

当然,如下有一些资料,胖友可以阅读参考:

下面,我们来进行 HikariCP 和 Druid 的入门,会配置单数据源和多数据源情况下的连接池。

2. HikariCP 单数据源

示例代码对应仓库:lab-19-datasource-pool-hikaricp-single

在本小节,我们会使用配置一个数据源的 HikariCP 连接池。

艿艿:推荐入门后,可以看看 HikariCP 的文档:https://github.com/brettwooldridge/HikariCP/wiki

2.1 引入依赖

pom.xml文件中,引入相关依赖

<?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>
  • 无需主动引入 HikariCP 的依赖。因为在 Spring Boot 2.X 中,spring-boot-starter-jdbc默认引入com.zaxxer.HikariCP依赖。

2.2 应用配置文件

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

spring:
  # datasource 数据源配置内容,对应 DataSourceProperties 配置属性类
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.jdbc.Driver
    username: root # 数据库账号
    password: # 数据库密码
    # HikariCP 自定义配置,对应 HikariConfig 配置属性类
    hikari:
      minimum-idle: 10 # 池中维护的最小空闲连接数,默认为 10 个。
      maximum-pool-size: 10 # 池中最大连接数,包括闲置和使用中的连接,默认为 10 个。
  • spring.datasource配置项下,我们可以添加数据源的通用配置。
  • spring.datasource.hikari配置项下,我们可以添加 HikariCP 连接池的自定义配置。然后DataSourceConfiguration.Hikari会自动化配置 HikariCP 连接池。

HikariCP 更多配置项,可以看看如下表格:s

FROM《HikariCP 连接池及其在 Spring Boot 中的配置》

配置项

描述

构造器默认值

默认配置validate之后的值

validate重置

autoCommit

自动提交从池中返回的连接

true

true

-

connectionTimeout

等待来自池的连接的最大毫秒数

SECONDS.toMillis(30) = 30000

30000

如果小于250毫秒,则被重置回30秒

idleTimeout

连接允许在池中闲置的最长时间

MINUTES.toMillis(10) = 600000

600000

如果idleTimeout+1秒>maxLifetime 且 maxLifetime>0,则会被重置为0(代表永远不会退出);如果idleTimeout!=0且小于10秒,则会被重置为10秒

maxLifetime

池中连接最长生命周期

MINUTES.toMillis(30) = 1800000

1800000

如果不等于0且小于30秒则会被重置回30分钟

connectionTestQuery

如果您的驱动程序支持JDBC4,我们强烈建议您不要设置此属性

null

null

-

minimumIdle

池中维护的最小空闲连接数

-1

10

minIdle<0或者minIdle>maxPoolSize,则被重置为maxPoolSize

maximumPoolSize

池中最大连接数,包括闲置和使用中的连接

-1

10

如果maxPoolSize小于1,则会被重置。当minIdle<=0被重置为DEFAULT_POOL_SIZE则为10;如果minIdle>0则重置为minIdle的值

metricRegistry

该属性允许您指定一个 Codahale / DropwizardMetricRegistry的实例,供池使用以记录各种指标

null

null

-

healthCheckRegistry

该属性允许您指定池使用的Codahale / Dropwizard HealthCheckRegistry的实例来报告当前健康信息

null

null

-

poolName

连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置

null

HikariPool-1

-

initializationFailTimeout

如果池无法成功初始化连接,则此属性控制池是否将fail fast

1

1

-

isolateInternalQueries

是否在其自己的事务中隔离内部池查询,例如连接活动测试

false

false

-

allowPoolSuspension

控制池是否可以通过JMX暂停和恢复

false

false

-

readOnly

从池中获取的连接是否默认处于只读模式

false

false

-

registerMbeans

是否注册JMX管理Bean(MBeans

false

false

-

catalog

为支持catalog概念的数据库设置默认catalog

driver default

null

-

connectionInitSql

该属性设置一个SQL语句,在将每个新连接创建后,将其添加到池中之前执行该语句。

null

null

-

driverClassName

HikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序,但对于一些较旧的驱动程序,还必须指定driverClassName

null

null

-

transactionIsolation

控制从池返回的连接的默认事务隔离级别

null

null

-

validationTimeout

连接将被测试活动的最大时间量

SECONDS.toMillis(5) = 5000

5000

如果小于250毫秒,则会被重置回5秒

leakDetectionThreshold

记录消息之前连接可能离开池的时间量,表示可能的连接泄漏

0

0

如果大于0且不是单元测试,则进一步判断:(leakDetectionThreshold < SECONDS.toMillis(2) or (leakDetectionThreshold > maxLifetime && maxLifetime > 0),会被重置为0 . 即如果要生效则必须>0,而且不能小于2秒,而且当maxLifetime > 0时不能大于maxLifetime

dataSource

这个属性允许你直接设置数据源的实例被池包装,而不是让HikariCP通过反射来构造它

null

null

-

schema

该属性为支持模式概念的数据库设置默认模式

driver default

null

-

threadFactory

此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例。

null

null

-

scheduledExecutor

此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例

null

null

-

2.3 Application

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

@SpringBootApplication
public class Application implements CommandLineRunner {

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

    @Autowired
    private DataSource dataSource;

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

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

}

通过实现CommandLineRunner接口,应用启动完成后,回调#run(String... args)方法,输出下 Connection 信息。执行日志如下:

2019-11-12 11:15:32.303  INFO 41198 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-11-12 11:15:32.472  INFO 41198 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-11-12 11:15:32.473  INFO 41198 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][获得连接:HikariProxyConnection@1561745898 wrapping com.mysql.jdbc.JDBC4Connection@793138bd]
  • 可以看到,HikariDataSource 成功初始化

3. HikariCP 多数据源

  • 示例代码对应仓库:lab-19-datasource-pool-hikaricp-multiple

    在本小节,我们会使用配置两个数据源的 HikariCP 连接池。

    3.1 引入依赖

    「2.1 引入依赖」是一致。

    3.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配置项下,定义了ordersusers两个数据源的配置。而每个数据源的配置,和我们在「2.2 应用配置文件」是一致的。3.3 数据源配置类

  • 3.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"配置项,所以这个问题就偷偷藏起来,**“不存在”**了。

3.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 BootDataSourceConfiguration.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数据源的配置,同上,就不重复解释了。

3.4 Application

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

@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);
        }
    }

}

执行日志如下:

2019-11-12 15:30:35.060  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-11-12 15:30:35.365  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-11-12 15:30:35.367  INFO 45868 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][ordersDataSource 获得连接:HikariProxyConnection@1041547629 wrapping com.mysql.jdbc.JDBC4Connection@3c989952]
2019-11-12 15:30:35.371  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2019-11-12 15:30:35.376  INFO 45868 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
2019-11-12 15:30:35.376  INFO 45868 --- [           main] c.i.s.lab19.datasourcepool.Application   : [run][usersDataSource 获得连接:HikariProxyConnection@795748540 wrapping com.mysql.jdbc.JDBC4Connection@7c098bb3]
  • 可以看到,两个 HikariDataSource 成功初始化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值