1. Обзор
В этой вводной статье мы узнаем о проекте пула соединений HikariCP JDBC. Это очень легкий (примерно 130 КБ) и молниеносный фреймворк для пула соединений JDBC, разработанный Бреттом Вулдриджем примерно в 2012 году.
2. Введение
Доступно несколько результатов тестов для сравнения производительности HikariCP с другими фреймворками пула соединений, такими как c3p0 , dbcp2 , tomcat и vibur . Например, команда HikariCP опубликовала следующие тесты (исходные результаты доступны здесь):

Фреймворк работает так быстро, потому что были применены следующие методы:
- Разработка на уровне байт-кода - была проделана некоторая экстремальная инженерия на уровне байт-кода (включая собственное кодирование на уровне сборки)
- Микрооптимизации - хотя их трудно измерить, в совокупности эти оптимизации повышают общую производительность.
- Разумное использование рамок Collections - ArrayList был заменен на пользовательский класс быстрым списком , который исключает проверки диапазона и удаление выполняет сканирование с хвоста до головы
3. Зависимость от Maven
Давайте создадим образец приложения, чтобы осветить его использование. HikariCP поддерживает все основные версии JVM. Каждая версия требует своей зависимости; для Java с 8 по 11 у нас есть:
com.zaxxer HikariCP 3.4.5
Также поддерживаются более старые версии JDK, такие как 6 и 7. Соответствующие версии можно найти здесь и здесь. Также мы можем проверить последние версии в Центральном репозитории Maven.
4. Использование
Теперь создадим демонстрационное приложение. Обратите внимание, что нам нужно включить подходящую зависимость класса драйвера JDBC в pom.xml . Если зависимости не указаны, приложение выдаст исключение ClassNotFoundException .
4.1. Создание DataSource
Мы будем использовать DataSource HikariCP для создания единственного экземпляра источника данных для нашего приложения:
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(); } }
Здесь следует отметить инициализацию в статическом блоке.
HikariConfig - это класс конфигурации, используемый для инициализации источника данных. Он поставляется с четырьмя хорошо известными обязательными параметрами: имя пользователя , пароль , jdbcUrl , dataSourceClassName .
Из jdbcUrl и dataSourceClassName можно использовать любой из них одновременно. Однако при использовании этого свойства со старыми драйверами нам может потребоваться установить оба свойства.
В дополнение к этим свойствам, есть несколько других доступных свойств, которые не все могут быть предложены другими фреймворками пула:
- autoCommit
- время соединения вышло
- idleTimeout
- maxLifetime
- connectionTestQuery
- connectionInitSql
- validationTimeout
- maximumPoolSize
- poolName
- allowPoolSuspension
- только для чтения
- транзакция
- утечкаDetectionThreshold
HikariCP выделяется этими свойствами базы данных. Он достаточно продвинут, чтобы самостоятельно обнаруживать утечки соединения!
Подробное описание этих свойств можно найти здесь.
Мы также можем инициализировать HikariConfig с файлом свойств, помещенным в каталог ресурсов :
private static HikariConfig config = new HikariConfig( "datasource.properties" );
Файл свойств должен выглядеть примерно так:
dataSourceClassName= //TBD dataSource.user= //TBD //other properties name should start with dataSource as shown above
Мы также можем использовать конфигурацию на основе 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 );
В качестве альтернативы мы можем инициализировать источник данных напрямую:
ds.setJdbcUrl( //TBD ); ds.setUsername( //TBD ); ds.setPassword( //TBD );
4.2. Использование источника данных
Теперь, когда мы определили источник данных, мы можем использовать его для получения соединения из настроенного пула соединений и выполнения действий, связанных с JDBC.
Предположим, у нас есть две таблицы с именами dept и emp, чтобы смоделировать вариант использования сотрудника и отдела. Мы напишем класс для извлечения этих деталей из базы данных с помощью HikariCP.
Ниже мы перечисляем операторы 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 );
Обратите внимание, если мы используем базу данных в памяти, такую как H2, нам необходимо автоматически загрузить скрипт базы данных перед запуском фактического кода для выборки данных. К счастью, H2 поставляется с параметром INIT, который может загружать сценарий базы данных из пути к классам во время выполнения. URL-адрес JDBC должен выглядеть так:
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:/db.sql'
Нам нужно создать метод для извлечения этих данных из базы данных:
public static List fetchData() throws SQLException { String SQL_QUERY = "select * from emp"; List 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 , мы можем ожидать, что размер возвращаемого списка должен быть равен количеству строк:
@Test public void givenConnection_thenFetchDbData() throws SQLException { HikariCPDemo.fetchData(); assertEquals( 4, employees.size() ); }
5. Заключение
В этом кратком руководстве мы узнали о преимуществах использования HikariCP и его конфигурации.
Как всегда, полный исходный код доступен на GitHub.