Introduction to HikariCP – HikariCP简介

最后修改: 2017年 5月 19日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this introductory tutorial, we’ll learn about the HikariCP JDBC connection pool project. This is a very lightweight (at roughly 130Kb) and lightning-fast JDBC connection pooling framework developed by Brett Wooldridge around 2012.

在这个入门教程中,我们将了解HikariCP JDBC连接池项目。这是一个非常轻量级(大约为130Kb)且快如闪电的JDBC连接池框架,由Brett Wooldridge在2012年左右开发。

2. Introduction

2.简介

There are several benchmark results available to compare the performance of HikariCP with other connection pooling frameworks, such as c3p0, dbcp2, tomcat, and vibur. For example, the HikariCP team published the below benchmarks (original results available here):

有几个基准结果可以用来比较HikariCP与其他连接池框架的性能,例如c3p0dbcp2tomcat,和vibur。例如,HikariCP团队发布了以下基准(原始结果可在这里)。

HikariCP-bench-2.6.0

The framework is so fast because the following techniques have been applied:

该框架之所以如此快速,是因为应用了以下技术。

  • Bytecode-level engineering – some extreme bytecode level engineering (including assembly level native coding) has been done
  • Micro-optimizations – although barely measurable, these optimizations combined boost the overall performance
  • Intelligent use of the Collections framework – the ArrayList<Statement> was replaced with a custom class, FastList, that eliminates range checking and performs removal scans from head to tail

3. Maven Dependency

3.Maven的依赖性

First, let’s build a sample application to highlight its usage. HikariCP comes with support for all the main versions of JVM. Each version requires its dependency. For Java 8 through 11, we have:

首先,让我们建立一个示例程序来强调它的用法。HikariCP对所有主要的JVM版本都有支持。每个版本都需要其依赖性。对于Java 8到11,我们有。

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

HikariCP also supports older JDK versions, like 6 and 7. The appropriate versions can be found here and here, respectively. We can also check the latest versions in the Central Maven Repository.

HikariCP也支持旧的JDK版本,如6和7。可以分别在这里这里找到相应的版本。我们还可以在Central Maven Repository中查看最新版本。

4. Usage

4.用法

Now we can create a demo application. Please note that we need to include a suitable JDBC driver class dependency in the pom.xml. If no dependencies are provided, the application will throw a ClassNotFoundException.

现在我们可以创建一个演示应用程序。请注意,我们需要在pom.xml中包含一个合适的JDBC驱动类依赖。如果没有提供依赖性,应用程序将抛出一个ClassNotFoundException

4.1. Creating a DataSource

4.1.创建一个数据源

We’ll use HikariCP’s DataSource to create a single instance of a data source for our application:

我们将使用HikariCP的DataSource来为我们的应用程序创建一个数据源的单一实例。

public class DataSource {

    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;

    static {
        config.setJdbcUrl( "jdbc_url" );
        config.setUsername( "database_username" );
        config.setPassword( "database_password" );
        config.addDataSourceProperty( "cachePrepStmts" , "true" );
        config.addDataSourceProperty( "prepStmtCacheSize" , "250" );
        config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );
        ds = new HikariDataSource( config );
    }

    private DataSource() {}

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

One point to note here is the initialization in the static block.

这里需要注意的一点是static块中的初始化。

HikariConfig is the configuration class used to initialize a data source. It comes with four well-known, must-use parameters: username, password, jdbcUrl, and dataSourceClassName.

HikariConfig是用于初始化数据源的配置类。它带有四个著名的、必须使用的参数。用户名密码jdbcUrldataSourceClassName

Out of jdbcUrl and dataSourceClassName, we generally use one at a time. However, when using this property with older drivers, we may need to set both properties.

jdbcUrldataSourceClassName中,我们一般一次使用一个。然而,当与较早的驱动程序一起使用该属性时,我们可能需要设置两个属性。

In addition to these properties, there are several other properties available that we may not find offered by other pooling frameworks:

除了这些属性之外,还有一些其他的属性,我们可能会发现其他的池子框架没有提供这些属性。

  • autoCommit
  • connectionTimeout
  • idleTimeout
  • maxLifetime
  • connectionTestQuery
  • connectionInitSql
  • validationTimeout
  • maximumPoolSize
  • poolName
  • allowPoolSuspension
  • readOnly
  • transactionIsolation
  • leakDetectionThreshold

HikariCP stands out because of these database properties. It’s even advanced enough to detect connection leaks by itself.

HikariCP因为这些数据库属性而脱颖而出。它甚至先进到可以自己检测连接泄漏。

A detailed description of the above properties can be found here.

上述属性的详细描述可在此处找到。

We can also initialize HikariConfig with a properties file placed in the resources directory:

我们也可以用放在resources目录下的属性文件来初始化HikariConfig

private static HikariConfig config = new HikariConfig(
    "datasource.properties" );

The properties file should look something like this:

属性文件应该看起来像这样。

dataSourceClassName= //TBD
dataSource.user= //TBD
//other properties name should start with dataSource as shown above

In addition, we can use java.util.Properties-based configuration:

此外,我们可以使用基于java.util.Properties-的配置。

Properties props = new Properties();
props.setProperty( "dataSourceClassName" , //TBD );
props.setProperty( "dataSource.user" , //TBD );
//setter for other required properties
private static HikariConfig config = new HikariConfig( props );

Alternatively, we can initialize a data source directly:

另外,我们也可以直接初始化一个数据源。

ds.setJdbcUrl( //TBD  );
ds.setUsername( //TBD );
ds.setPassword( //TBD );

4.2. Using a Data Source

4.2.使用数据源

Now that we have defined the data source, we can use it to obtain a connection from the configured connection pool, and perform JDBC related actions.

现在我们已经定义了数据源,我们可以用它来从配置的连接池中获得一个连接,并执行JDBC相关的操作。

Suppose we have two tables, named dept and emp, to simulate an employee-department use case. We’ll write a class to fetch those details from the database using HikariCP.

假设我们有两个表,名为deptemp,来模拟一个雇员-部门的用例。我们将编写一个类,使用HikariCP从数据库中获取这些细节。

Below we’ll list the SQL statements necessary to create the sample data:

下面我们将列出创建样本数据所需的SQL语句。

create table dept(
  deptno numeric,
  dname  varchar(14),
  loc    varchar(13),
  constraint pk_dept primary key ( deptno )
);
 
create table emp(
  empno    numeric,
  ename    varchar(10),
  job      varchar(9),
  mgr      numeric,
  hiredate date,
  sal      numeric,
  comm     numeric,
  deptno   numeric,
  constraint pk_emp primary key ( empno ),
  constraint fk_deptno foreign key ( deptno ) references dept ( deptno )
);

insert into dept values( 10, 'ACCOUNTING', 'NEW YORK' );
insert into dept values( 20, 'RESEARCH', 'DALLAS' );
insert into dept values( 30, 'SALES', 'CHICAGO' );
insert into dept values( 40, 'OPERATIONS', 'BOSTON' );
 
insert into emp values(
 7839, 'KING', 'PRESIDENT', null,
 to_date( '17-11-1981' , 'dd-mm-yyyy' ),
 7698, null, 10
);
insert into emp values(
 7698, 'BLAKE', 'MANAGER', 7839,
 to_date( '1-5-1981' , 'dd-mm-yyyy' ),
 7782, null, 20
);
insert into emp values(
 7782, 'CLARK', 'MANAGER', 7839,
 to_date( '9-6-1981' , 'dd-mm-yyyy' ),
 7566, null, 30
);
insert into emp values(
 7566, 'JONES', 'MANAGER', 7839,
 to_date( '2-4-1981' , 'dd-mm-yyyy' ),
 7839, null, 40
);

Please note, if we use an in-memory database such as H2, we need to automatically load the database script before running the actual code to fetch the data. Thankfully, H2 comes with an INIT parameter that can load the database script from the classpath at runtime. The JDBC URL should look like:

请注意,如果我们使用H2这样的内存数据库,我们需要在运行实际代码获取数据之前自动加载数据库脚本。值得庆幸的是,H2有一个INIT参数,可以在运行时从classpath加载数据库脚本。JDBC的URL应该是这样的。

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:/db.sql'

We need to create a method to fetch this data from the database:

我们需要创建一个方法来从数据库中获取这些数据。

public static List<Employee> fetchData() throws SQLException {
    String SQL_QUERY = "select * from emp";
    List<Employee> employees = null;
    try (Connection con = DataSource.getConnection();
        PreparedStatement pst = con.prepareStatement( SQL_QUERY );
        ResultSet rs = pst.executeQuery();) {
            employees = new ArrayList<>();
            Employee employee;
            while ( rs.next() ) {
                employee = new Employee();
                employee.setEmpNo( rs.getInt( "empno" ) );
                employee.setEname( rs.getString( "ename" ) );
                employee.setJob( rs.getString( "job" ) );
                employee.setMgr( rs.getInt( "mgr" ) );
                employee.setHiredate( rs.getDate( "hiredate" ) );
                employee.setSal( rs.getInt( "sal" ) );
                employee.setComm( rs.getInt( "comm" ) );
                employee.setDeptno( rs.getInt( "deptno" ) );
                employees.add( employee );
            }
	} 
    return employees;
}

Then we need to create a JUnit method to test it. Since we know the number of rows in the table emp, we can expect that the size of the returned list should be equal to the number of rows:

然后我们需要创建一个JUnit方法来测试它。由于我们知道表emp中的行数,我们可以预期返回列表的大小应该等于行数。

@Test
public void givenConnection_thenFetchDbData() throws SQLException {
    HikariCPDemo.fetchData();
 
    assertEquals( 4, employees.size() );
}

5. Conclusion

5.结论

In this brief article, we learned the benefits of using HikariCP, and its configuration.

在这篇简短的文章中,我们了解了使用HikariCP的好处,以及它的配置。

As always, the full source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得