概述
本教程将带你快速了解 HikariCP JDBC 连接池项目。这是一个极其轻量(约130Kb)且性能炸裂的JDBC连接池框架,由 Brett Wooldridge 在2012年左右开发。
简介
网上有不少基准测试对比了HikariCP与其他连接池框架(如*c3p0、dbcp2、tomcat* 和 vibur)的性能。例如HikariCP团队发布的基准测试结果(原始数据在此):
框架之所以这么快,主要归功于这些技术:
- 字节码级工程——进行了大量极端的字节码优化(甚至包括汇编级别的本地代码)
- 微优化——虽然单个优化效果微不足道,但组合起来显著提升整体性能
- 智能集合框架使用——用自定义的
FastList
替代了ArrayList<Statement>
,消除了范围检查并优化了移除扫描逻辑
Maven依赖
先构建一个示例应用来演示用法。HikariCP支持所有主流JVM版本,每个版本对应不同依赖。Java 8-11使用:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
</dependency>
也支持旧版JDK(如6/7),具体版本可查看这里和这里。最新版本可在Maven中央仓库查询。
使用
现在创建演示应用。注意需在 pom.xml
添加合适的JDBC驱动依赖,否则会抛出 ClassNotFoundException
。
创建数据源
用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();
}
}
⚠️ 注意初始化在 static
代码块中完成。
HikariConfig 是初始化数据源的配置类,包含四个核心参数:username
、password
、jdbcUrl
和 dataSourceClassName
。
✅ jdbcUrl
和 dataSourceClassName
通常二选一使用,但旧版驱动可能需要同时设置。
除基础参数外,还提供其他框架少见的特性:
-
autoCommit
-
connectionTimeout
-
idleTimeout
-
maxLifetime
-
connectionTestQuery
-
connectionInitSql
-
validationTimeout
-
maximumPoolSize
-
poolName
-
allowPoolSuspension
-
readOnly
-
transactionIsolation
-
leakDetectionThreshold
HikariCP的亮点就是这些数据库属性,甚至能自动检测连接泄漏!详细参数说明见官方文档。
也可通过 resources
目录下的属性文件初始化:
private static HikariConfig config = new HikariConfig(
"datasource.properties" );
属性文件格式示例:
dataSourceClassName= //TBD
dataSource.user= //TBD
//其他属性需以dataSource.开头
或使用 java.util.Properties
配置:
Properties props = new Properties();
props.setProperty( "dataSourceClassName" , //TBD );
props.setProperty( "dataSource.user" , //TBD );
//设置其他必需属性
private static HikariConfig config = new HikariConfig( props );
甚至直接初始化数据源:
ds.setJdbcUrl( //TBD );
ds.setUsername( //TBD );
ds.setPassword( //TBD );
使用数据源
定义好数据源后,就能从连接池获取连接并执行JDBC操作。
假设有两个表 dept
和 emp
模拟员工-部门场景。我们写个类用HikariCP获取数据:
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
);
⚠️ 若用H2内存数据库,需在运行前自动加载脚本。H2的 INIT
参数可从类路径加载脚本:
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:/db.sql'
创建数据获取方法:
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;
}
用JUnit测试(已知 emp
表有4行数据):
@Test
public void givenConnection_thenFetchDbData() throws SQLException {
HikariCPDemo.fetchData();
assertEquals( 4, employees.size() );
}
总结
本文介绍了HikariCP的优势及配置方法。简单粗暴地说,如果你追求极致性能,它就是最佳选择。
完整源码见GitHub仓库。