Въведение в HikariCP

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.