Aquest how-to va dirigit principalment al personal tècnic (desenvolupadors, analistes tècnics i arquitectes) que desenvolupin una aplicació Canigó 3.2 i tinguin la necessitat de treballar amb un Connection Pool d’alt rendiment.
Els pools de connexions proporcionen una millora en el rendiment de les consultes SQL, minimitzant el temps d’adquisició i ús de les connexions a BBDD. Les diferents maneres de gestionar aquestes connexions i l’oferta de funcionalitats relacionades fa que hi hagi diferents implementacions (Apache DBCP2, Hikari CP, C3P0, Tomcat Pool, etc.)
Hikari CP és un pool de connexions que actualment té un gran momentum degut principalment a una visió minimalista de la gestió de les connexions, fent que frameworks molt populars (com Spring) l’hagin triat com una opció més per la tasca de gestionar les connexions a BBDD.
Els exemples i configuracions estan adaptats específicament per una aplicació estàndard de Canigó, tot i que es fàcilment adaptable a aplicacions J2EE més genèriques.
Hikari actualment proporciona 3 versions, segons la versió de Java sigui 8+ o prèvies; tot i que les versions per Java 7 i 6 estan només en mode de manteniment. Segons la versió de Java s’ha de triar la dependència Maven apropiada:
<!-- Java 8+ -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Java 7 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.4.7</version>
</dependency>
<!-- Java 6 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.3.13</version>
</dependency>
De manera ad-hoc s’ha definit per Canigó que les propietats específiques del pool de connexions de Hikari tinguin el prefix persistence.hikari
; agrupant la configuració de les propietats del pool de connexions en 3 parts:
Un exemple de configuració de Hikari per Canigó seria el següent:
#
# HikariCP
#
# 1. Accés / Autenticació
# 1.a JDNI
#*.persistence.hikari.jndiName=java:comp/env/jdbc/OracleIntranetDS
# 1.b. JDBC Auth
*.persistence.hikari.jdbc.url=jdbc:h2:mem:bbdd_proves;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false
*.persistence.hikari.jdbc.username=sa
*.persistence.hikari.jdbc.password=
# 2. Pool configuration
# 20s
*.persistence.hikari.connectionTimeout=20000
# 4m
*.persistence.hikari.maxLifetime=240000
# Recomanació genèrica: 10 (per aplicacions web intranet), 20 (per aplicacions amb processos batch/nocturns), 50 (per aplicacions web extranet). Finalment 100+ (per grans aplicacions amb molts usuaris concurrents i/o transaccions lentes, OLAP, data Warehouse, etc.)
*.persistence.hikari.maximumPoolSize=10
# 3. JDBC Driver (MySql) específic
# Exemple de https://github.com/brettwooldridge/HikariCP#initialization
*.persistence.hikari.driver.cachePrepStmts=true
*.persistence.hikari.driver.prepStmtCacheSize=500
*.persistence.hikari.driver.prepStmtCacheSqlLimit=2048
*.persistence.hikari.driver.useServerPrepStmts=true
*.persistence.hikari.driver.useLocalSessionState=true
*.persistence.hikari.driver.rewriteBatchedStatements=true
*.persistence.hikari.driver.cacheResultSetMetadata=true
*.persistence.hikari.driver.cacheServerConfiguration=true
*.persistence.hikari.driver.elideSetAutoCommits=true
*.persistence.hikari.driver.maintainTimeStats=false
La creació del DataSource s’ha de definir de la següent manera:
/**
* NOTA: Sobreescrivim el bean "dataSource" creat anteriorment per a què, amb el
* mateix àlies, sigui retornat el DS de Hikari.
*
* @param configuration
* @param configurer
* @return
*/
@Bean(name = { "hikariDataSource", "dataSource" }, destroyMethod = "close")
@Primary
public DataSource hikariDataSource(final PropertiesConfiguration configuration,
final ICustomPropertyPlaceHolderConfigurer configurer) {
final DataSource ds = init(new HikariDataSource(), "persistence.hikari.", //
configuration, configurer.getResolvedProps());
if (logger.isDebugEnabled())
logger.debug(ToStringBuilder.reflectionToString(ds));
return ds;
}
protected DataSource init(final HikariDataSource ds, final String prefix,
final PropertiesConfiguration configuration, final Map<String, String> properties) {
final String jndiName = configuration.getProperty(prefix + "jndiName");
final String jdbcUrl = configuration.getProperty(prefix + "jdbc.url");
if (jndiName != null && jdbcUrl != null)
logger.warn("jndiName i jdbcUrl estan definits alhora per " + prefix);
if (jndiName != null) {
ds.setDataSourceJNDI(jndiName);
} else {
ds.setJdbcUrl(jdbcUrl);
ds.setUsername(configuration.getProperty(prefix + "jdbc.username"));
ds.setPassword(configuration.getProperty(prefix + "jdbc.password"));
}
ds.setConnectionTimeout(new Integer(configuration.getProperty(prefix + "connectionTimeout"))); // ~20s
ds.setValidationTimeout(Math.max(ds.getConnectionTimeout() / 5, 5 * 1000)); // 20% connectionTimeout
//
final int MINUTE = 60 * 1000;
ds.setMaxLifetime(new Integer(configuration.getProperty(prefix + "maxLifetime"))); // ~4m
ds.setIdleTimeout(Math.max( //
Math.min(ds.getMaxLifetime() - MINUTE, 4 * MINUTE) //
, 10 * 1000));
//
ds.setMaximumPoolSize(new Integer(configuration.getProperty(prefix + "maximumPoolSize"))); // ~20
ds.setMinimumIdle(Math.max(ds.getMaximumPoolSize() / 10, 1)); // [ 10% maximumPoolSize, 1]
//
// Definició de les propietats : persistence.hikari.driver.XYZ ->
// ds.addDataSourceProperty(XYZ, *)
//
for (final Entry<String, String> entry : properties.entrySet()) {
final String key = entry.getKey();
if (key.startsWith(prefix + "driver.")) {
final String property = key.substring((prefix + "driver.").length());
ds.addDataSourceProperty(property, parse(entry.getValue()));
}
}
return ds;
}
protected Object parse(final String value) {
try {
return new Integer(value);
} catch (NumberFormatException e) {
logger.debug(e.getMessage());
}
if ("true".equals(value))
return true;
if ("false".equals(value))
return false;
return value;
}
A continuació es defineix una llista d’enllaços amb informació addicional per poder aprofundir en els diferents aspectes i opcions mostrades al document.
El archetype per aplicacions REST de Canigó plugin-canigo-archetype-rest
genera actualment un exemple funcional amb Swagger. Aquest exemple, per defecte, no s’integra amb Hikari de manera que per fer-ne ús del Hikari, només cal modificar el fitxer src/main/resources/spring/app-custom-persistence-jpa.xml
de la següent manera:
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:initialize-database data-source="hikariDataSource" >
<jdbc:script location="classpath:scripts/h2/db-app-h2db-schema.sql"/>
<jdbc:script location="classpath:scripts/h2/db-app-h2db-data.sql"/>
</jdbc:initialize-database>