Spring Boot 中使用 Hikari,给我整不会了

6,923 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

最近自己使用 Spring boot 搭建了一个非常简单的项目,可是不知道为啥控制台总是出现

Thread starvation or clock leap detected (housekeeper delta=3h24s779ms457µs999ns).

气的我直接找到源码,GitHub 一顿查询。最终解决了问题,开心。

我是使用 Spring Boot 2.5.4 我们都知道 Spring boot 默认就依赖了 Hikari ,而我的 JDK 版本是 11 ,这里就有问题了 Spring boot 的默认版本和官方推荐 JDK11 使用的版本不一致,对应于 JDK 11, 建议使用 5.0.0 的 Hikari 。

Hikari 介绍

不知道怎么搞的,我一直隐约感觉 Hikari 是阿里的框架,直到我打开 GitHub 啊,这不对啊,这好像是个日本的程序员写的呢?刚好说说这个名字,Hikari 怎么读的呢?可以读成 ”黑卡瑞“ ,大致看了一下 GitHub 的介绍,大呼一声,真秀!一个中国人在看日本人用英语写的文档,总感觉哪里怪怪的,但又说不上来。

说回到 Hikari ,它是一个连接池,官方给了这么几个形容词,fast,simple,reliable,zero-overhead,very light. 嗯听起来很好对吧,据说是史上最快的连接池。

我这里引用一句官方的话

The HikariCP design aesthetic is Minimalism. In keeping with the simple is better or less is more design philosophy, some configuration axis are intentionally left out.

Hikari 的设计美学是极简主义,少即是多的哲学,为此它还刻意减少一些参数,这点真的是直击我心。less is more and keep it simple and stupid.

在 GitHub 上作者甚至还介绍了他的优化点,都是一些比较小的点,但正是这些小的点汇集起来了,才使得 Hikari 的性能这么给力。优化的点是什么我就不具体说了,像什么缓存,静态方法,重写 ArrayList ...

Hikari 的使用

作为开发者的我们,使用 Hikari 还是非常简单的,以我使用的 MySQL 为例,JDK 11 配置了 5.0.0 版本的 Hikari.

1 引入依赖

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>5.0.0</version>
        </dependency>

2 初始化

如果不是看官网,我不曾知道原来有这么多的初始化方式,我要一一的列举出来,扩展大家的思路。

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons");
config.setUsername("bart");
config.setPassword("51mp50n");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
​
HikariDataSource ds = new HikariDataSource(config);

或者直接这样

HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons");
ds.setUsername("bart");
ds.setPassword("51mp50n");
...

或者基于配置文件的初始化

HikariConfig config = new HikariConfig("/some/path/hikari.properties");
HikariDataSource ds = new HikariDataSource(config);
​
​
// properties file
dataSourceClassName=org.postgresql.ds.PGSimpleDataSource
dataSource.user=test
dataSource.password=test
dataSource.databaseName=mydb
dataSource.portNumber=5432
dataSource.serverName=localhost

或者直接使用 Properties 类

Properties props = new Properties();
props.setProperty("dataSourceClassName", "org.postgresql.ds.PGSimpleDataSource");
props.setProperty("dataSource.user", "test");
props.setProperty("dataSource.password", "test");
props.setProperty("dataSource.databaseName", "mydb");
props.put("dataSource.logWriter", new PrintWriter(System.out));
​
HikariConfig config = new HikariConfig(props);
HikariDataSource ds = new HikariDataSource(config);

甚至还可以配置环境变量

There is also a System property available, hikaricp.configurationFile,

看到以上这些初始化的方法,直呼过瘾。

项目配置中的常用参数讲解

以为搭建的 Spring boot 项目为例,看看我的配置吧。

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost/database?useUnicode=true&characterEncoding=utf8
    username: root
    password: root
    hikari:
        minimum-idle: 10
        idle-timeout: 30000
        maximum-pool-size: 20
        max-lifetime: 120000
        connection-timeout: 30000

根据 less is more 的设计哲学,以 Hikari 开头的配置都是可选的配置,都有默认的值,不配也行哈。

autoCommit: 默认是 true,自动提交从池中返回的连接。

connectionTimeout:等待来自池的连接的最大毫秒数,默认为 30000 ms = 30 s,允许最小时间是 250 毫秒,如果小于 250 毫秒,则被重置回 30 秒。

idleTimeout: 连接允许在池中闲置的最长时间,默认为 600000,即 10 分钟。如果 idleTimeout + 1 秒 > maxLifetime 且 maxLifetime > 0,则会被重置为 0(代表永远不会退出);如果 idleTimeout != 0 且小于 10 秒,则会被重置为 10 秒。只有当 minimumIdle 小于 maximumPoolSize 时,这个参数才生效,当空闲连接数超过 minimumIdle,而且空闲时间超过 idleTimeout,则会被移除。

keepaliveTime:连接存活时间,这个值必须小于 maxLifetime 值。Keepalive "只会发生在空闲的连接上。当对一个给定的连接进行 "keepalive "的时间到了,该连接将从池中移除。允许的最小值是 30000 ms(30秒),但最理想的值是在分钟范围内。默认值:0

maxLifetime:池中连接最长生命周期。默认为 1800000,如果不等于 0 且小于 30 秒则会被重置回 30 分钟。强烈建议设置这个参数。

minimumIdle:控制连接池空闲连接的最小数量,当连接池空闲连接少于 minimumIdle,而且总共连接数不大于 maximumPoolSize 时,HikariCP 会尽力补充新的连接。为了性能考虑,不建议设置此值,而是让 HikariCP 把连接池当做固定大小的处理,默认 minimumIdle 与 maximumPoolSize 一样。当 minIdle < 0 或者 minIdle > maxPoolSize,则被重置为 maxPoolSize,该值默认为 10。

maximumPoolSize:池中最大连接数,包括闲置和使用中的连接。默认为 10。如果 maxPoolSize 小于1,则会被重置。当 minIdle <=0 被重置为DEFAULT_POOL_SIZE 则为 10;如果 minIdle > 0 则重置为 minIdle 的值。

poolName:连接池的用户定义名称,主要出现在日志记录和 JMX 管理控制台中以识别池和池配置。默认为 HikariPool-1。

readOnly:从池中获取的连接是否默认处于只读模式。默认为 false。这个属性工作与否取决于数据库的实现。

connectionTestQuery:如果你的驱动程序支持 JDBC4,我们强烈建议不要设置这个属性。这是针对不支持 JDBC4 Connection.isValid() API的 "传统 "驱动程序。这是一个查询,在一个连接从池子里给你之前会被执行,以验证与数据库的连接是否仍然有效。同样,尝试在没有这个属性的情况下运行数据库池,如果你的驱动不符合JDBC4标准,HikariCP 会记录一个错误,让你知道。默认值:无。

最后

说一下我的那个警告是怎么解决的吧,更新了 jar 包,更改了配置,idle-timeout 要小于 max-lifetime 的呀,开始不知道在哪里 copy 的,他们的值不对,就很气…… 好吧也怪自己没有好好研究,就直到 copy paste。 官方才是最香的,看看官方文档,这波不亏。