1. Общ преглед
В тази уводна статия ще научим за проекта за свързване на HikariCP JDBC. Това е много лека (с приблизително 130Kb) и светкавична JDBC рамка за обединяване на връзки, разработена от Brett Wooldridge около 2012 г.
2. Въведение
Има няколко резултати бенчмарк налице за сравняване на ефективността на HikariCP с други обединяване връзка рамки като C3P0 , dbcp2 , котарак и vibur . Например екипът на HikariCP публикува по-долу еталони (оригиналните резултати са налични тук):

Рамката е толкова бърза, защото са приложени следните техники:
- Инженеринг на ниво байткод - направено е някакво екстремно инженерство на ниво байт код (включително собствено кодиране на ниво сборка)
- Микро оптимизации - макар и едва измерими, тези оптимизации комбинират повишаване на цялостната производителност
- Интелигентно използване на рамката за Събиране на вземания - на ArrayList е заменен с клас по поръчка Fastlist , елиминирани от диапазон проверка и отстраняване изпълнява сканиране от опашката към главата
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 на 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
- connectionTimeout
- idleTimeout
- maxLifetime
- connectionTestQuery
- connectionInitSql
- validationTimeout
- maximumPoolSize
- poolName
- allowPoolSuspension
- Само за четене
- transactionIsolation
- leakDetectionThreshold
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.