介绍
HikariCP 号称是 史上性能最好 的数据库连接池,从15年推出以来,已经经受了广大应用市场的考验,并且成功地被SpringBoot2.0作为默认数据库连接池进行推广,在可靠性上面是值得信任的。其次借助于其代码量少,占用cpu和内存量小的优点,使得它的执行率非常高。最后,Spring配置HikariCP和druid基本没什么区别,迁移过来非常方便,这些都是为什么HikariCP目前如此受欢迎的原因。
优化
Hikari相比起其它连接池的性能高了非常多,那么,这是怎么做到的呢?通过查看HikariCP官网介绍,对于HikariCP所做优化总结如下:
字节码精简 :优化代码,编译后的字节码量极少,使得CPU缓存可以加载更多的程序代码;
HikariCP在优化并精简字节码上也下了功夫,使用第三方的Java字节码修改类库Javassist来生成委托实现动态代理.动态代理的实现在ProxyFactory类,速度更快,相比于JDK Proxy生成的字节码更少,精简了很多不必要的字节码。优化代理和拦截器:减少代码,例如HikariCP的Statement proxy只有100行代码,只有BoneCP的十分之一;
自定义数组类型(FastStatementList)代替ArrayList:避免ArrayList每次get()都要进行range check,避免调用remove()时的从头到尾的扫描(由于连接的特点是后获取连接的先释放);
自定义集合类型(ConcurrentBag):提高并发读写的效率;
关于Connection的操作:另外在Java代码中,很多都是在使用完之后直接关闭连接,以前都是从头到尾遍历,来关闭对应的Connection,而HikariCP则是从尾部对Connection集合进行扫描,整体上来说,从尾部开始的性能更好一些。
对比
依赖
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.1.0</version>
</dependency>
或
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
配置
HikariCP 所有时间相关的参数单位都为 ms。
详细的配置说明可参考官网文档:https://github.com/brettwooldridge/HikariCP
基本配置
| 参数 | 默认值 | 描述 | |||
|---|---|---|---|---|---|
| dataSourceClassName | none | 驱动里面数据源的类名称;不支持 | XA数据源,各数据源对应的数据源类名可参见 | ”2、数据源类名“ | |
| jdbcUrl | none | 连接 | url;该参数与 | dataSourceClassName | 设置一个即可 |
| username | none | 用户名 | |||
| password | none | 密码 |
常用配置
| 参数 | 默认值 | 描述 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| autoCommit | true | 连接返回连接池时,是否自动提交事务 | ||||||||
| connectionTimeout | 30000 | 从连接池获取连接的最大超时时间 | ||||||||
| idleTimeout | 60000 | 空闲连接存活的最大时间,当空闲连接数>minimumIdle | 且 | 连接的空闲状态时间>idleTimeout | 时,将把该连接从连接池中删除;只有当 | minimumIdle | < | maximumPoolSize | 时,该设置才生效;0 | 表示永不超时 |
| keepaliveTime | 0 | 保持空闲连接可用的检测频率,单位:ms;0 | 表示不检测 | |||||||
| maxLifetime | 1800000 | 连接存活的最大时间;0 | 表示没有限制 | |||||||
| connectionTestQuery | none | 连接检测的查询语句;如果驱动支持 | JDBC | 4,强烈建议不要设置此参数 | ||||||
| minimumIdle | same | as | maximumPoolSize | 最小空闲连接数;为了提高性能,建议不要设置此参数,使连接池为固定大小 | ||||||
| maximumPoolSize | 10 | 最大连接数 | ||||||||
| metricRegistry | none | 该参数仅通过编程配置或 | IoC | 容器可用;该参数用于指定池使用的 | Codahale/Dropwizard | MetricRegistry实例来记录各种指标。 | ||||
| healthCheckRegistry | none | 该参数仅通过编程配置或 | IoC | 容器可用;该参数用于指定池使用的 | Codahale/Dropwizard | HealthCheckRegistry实例来记录健康信息。 | ||||
| poolName | auto-generated | 连接池名称 |
不常用配置
| 参数 | 默认值 | 描述 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| initializationFailTimeout | 1 | 启动连接池时不能成功初始化连接,是否快速失败。>0 | 时,会尝试获取连接。如果获取时间超过指定时长(connectionTimeout | + | initializationFailTimeout),不会开启连接池,并抛出异常。=0 | 时,会尝试获取并验证连接。如果获取成功但验证失败则不开启池,但是如果获取失败还是会开启池。<0 |
时,直接启动连接池,不进行初始化连接尝试。 | ||||||
| isolateInternalQueries | false | 是否在事务中隔离 | HikariCP | 自己的查询;autoCommit | 为 | false | 时,该设置生效 | ||||||
| allowPoolSuspension | false | 是否允许通过 | JMX | 挂起和恢复连接池;挂起时获取连接不会超时,知道连接池恢复 | |||||||||
| readOnly | false | 连接是否只读 | |||||||||||
| registerMbeans | false | 是否开启 | JMX | ||||||||||
| catalog | driver | default | 默认的数据库 | catalog | |||||||||
| connectionInitSql | none | 连接池初始化后执行的 | SQL | ||||||||||
| driverClassName | none | 驱动类名;HikariCP | 会尝试通过 | jdbcUrl | 来确定 | driverClassName,但对一些老的驱动必须指定 | driverClassName;可以忽略该配置除非报 | “the | driver | was | not | found” | 的错误。 |
| transactionIsolation | driver | default | 默认的事务隔离级别 | ||||||||||
| validationTimeout | 5000 | 连接检测的超时时间;必须大于 | connectionTimeout,最小允许的值为 | 250 | |||||||||
| leakDetectionThreshold | 0 | 连接可以被借出多久;超过该时间将打印连接可能泄露的日志,最小允许的值为 | 2000,单位 | ms | |||||||||
| dataSource | none | 指定数据源;此参数仅通过编程配置或 | IoC | 容器可用,当设置此参数,dataSourceClassName | 和所有 | DataSource- | 相关的属性将被忽略。 | ||||||
| schema | driver | default | 默认的数据库 | schema | |||||||||
| threadFactory | none | 指定连接池用于创建线程的 | java.util.concurrent.ThreadFactory | 实例;此参数仅通过编程配置或 | IoC | 容器可用 | |||||||
| scheduledExecutor | none | 指定连接池用于执行定时任务的 | java.util.concurrent.ScheduledExecutorService | 实例;此参数仅通过编程配置或 | IoC | 容器可用 |
例子
package com.abc.demo.general.dbpool;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class HikariCPCase {
private static Logger logger = LoggerFactory.getLogger(HikariCPCase.class);
/**
* 使用 dataSourceClassName
*/
@Test
public void test1() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setPoolName("HikariCP 连接池");
hikariConfig.setDataSourceClassName("oracle.jdbc.pool.OracleDataSource");
hikariConfig.addDataSourceProperty("user", "test");
hikariConfig.addDataSourceProperty("password", "123456");
hikariConfig.addDataSourceProperty("url", "jdbc:oracle:thin:@10.49.196.10:1521:test");
hikariConfig.setMaximumPoolSize(15);
HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
Connection connection = null;
try {
connection = hikariDataSource.getConnection();
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("select * from v$version");
if (rs.next()) {
logger.info(rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(connection);
}
//实际使用中一般是在应用启动时初始化数据源,应用从数据源中获取连接;并不会关闭数据源。
hikariDataSource.close();
}
/**
* 使用jdbc-url
*/
@Test
public void test2() {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setPoolName("HikariCP 连接池");
hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariConfig.setJdbcUrl("jdbc:mysql://10.49.196.11:3306/mydb?useUnicode=true&characterEncoding=UTF-8");
hikariConfig.setUsername("root");
hikariConfig.setPassword("123456");
hikariConfig.setMinimumIdle(2);
hikariConfig.setMaximumPoolSize(10);
HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
Connection connection = null;
try {
connection = hikariDataSource.getConnection();
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("select version()");
if (rs.next()) {
logger.info(rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(connection);
}
//实际使用中一般是在应用启动时初始化数据源,应用从数据源中获取连接;并不会关闭数据源。
hikariDataSource.close();
}
private static void close(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
参考:
https://blog.csdn.net/weixin_59383491/article/details/131437532
https://www.cnblogs.com/wuyongyin/p/15560017.html
