[Java/Spring] HikariCP
To connect to a database in a Java application using the JDBC (Java Database Connectivity) API, Connection instances must be obtained via the DataSource interface. DataSource is the standard interface defined by the JDBC specification for creating Connection instances. Because DataSource implementations all implement the common interfaces of the JDBC specification, they can be swapped at any time. These DataSource implementations differ in features such as connection pooling and distributed transaction support, and in detailed configuration options related to database connections.
The Spring Framework provides DataSource implementations such as DriverManagerDataSource and SingleConnectionDataSource, but these do not provide connection pooling and are therefore mainly used for testing. DriverManagerDataSource opens a new connection each time a client requests one, which is not resource-efficient, and SingleConnectionDataSource, a subclass of DriverManagerDataSource, reuses a single connection and does not close it, making it unsuitable for multithreaded environments.
HikariCP and Apache Commons DBCP are open-source implementations of the DataSource interface. Since Spring 2.0, HikariCP has been included as the default implementation instead of DBCP.
HikariCP properties
Idle Timeout (idleTimeout)
The idleTimeout property controls the maximum amount of time that a connection may remain idle in the pool. This setting only applies when the minimum idle connections (minimumIdle) is defined to be less than the maximum pool size (maximumPoolSize). When the pool reaches the minimum idle connections, idle connections will not be removed. Whether a connection is terminated as idle may vary by up to +30 seconds, with an average of +15 seconds. Connections will not be terminated before the idle timeout elapses. A value of 0 means idle connections are never removed from the pool. The allowed minimum value is 10000 (10 seconds) and the default is 600000 (10 minutes).
Maximum Lifetime (maxLifeTime)
The maxLifeTime property controls the maximum lifetime of a connection in the pool. Connections that are in use will never be removed; only connections that are closed may be removed. Setting maxLifeTime does not cause all connections in the pool to be removed at once; a slight negative jitter is applied (the lifetime for each connection is reduced by up to 2.5% of the maxLifeTime value) to deliberately avoid mass expiration of the pool.
It is recommended to set the maxLifeTime property and to set it a few seconds shorter than the database’s configured connection timeout, taking network latency into account. A value of 0 means there is no maximum lifetime (infinite lifetime); in this case connections are not removed even when closed, but the idleTimeout setting still applies. The allowed minimum value is 30000 (30 seconds) and the default is 1800000 (30 minutes).
If the database closes a connection because its connection timeout (for example, MySQL’s WAIT_TIMEOUT or Oracle’s IDLE_TIME) has elapsed, the database will terminate the connection regardless of the application’s settings. If the maxLifeTime value is longer than the database’s connection timeout, the application may perform validity checks on a connection after the database has closed it, which can result in errors like the following:
MyDataSource - Failed to validate connection ConnectionID:384 ClientConnectionId: eae60768-5342-4d5f-a134-c1309b87a17a (The connection is closed.). Possibly consider using a shorter maxLifetime value.
To prevent the above error, set the maxLifeTime property a few seconds shorter than the database’s connection timeout.
Connection Test Query (connectionTestQuery)
The connection test query is a query that is executed just before a connection is handed out from the pool to verify that the connection is still valid. JDBC4 verifies a connection’s validity using Connection.isValid() instead of executing a test query, and the exact mechanism may vary by implementation. The connectionTestQuery property is intended for legacy drivers that do not support JDBC4’s Connection.isValid() API; if the JDBC driver supports JDBC4, it is recommended not to set this property. If the driver is not JDBC4-compliant and the connection test query property is not used, HikariCP will throw an error. The default value is none.
When the JDBC driver supports JDBC4 and the connection test query property is not set, the isUseJdbc4Validation property of PoolBase becomes true and the isConnectionDead() method will use JDBC4’s Connection.isValid() to check connection validity.
Using JDBC4’s Connection.isValid() for connection validation is not always strictly faster than using a connection test query. Implementations may execute a simple dummy query, or they may use a low-level internal ping method instead of running a dummy query, so it is advisable to check the exact mechanism used by the driver implementation.
Maximum Pool Size (maximumPoolSize)
The maximumPoolSize property controls the maximum size that the connection pool can reach, including both idle and in-use connections. By default, this value determines the actual maximum number of database connections the application will use. Choose an appropriate value based on the runtime environment. When the pool reaches this size and there are no idle connections available, getConnection() calls will block for up to connectionTimeout milliseconds before timing out. The default is 10.
Spring Boot DataSource bean configuration and HikariCP property settings
Spring Boot automatically creates a DataSource bean and configures its properties by detecting application property settings. If you set the database connection information in the common spring.datasource properties, a DataSource bean is created with the corresponding values and registered in the application context.
spring:
datasource:
url:
username:
password:
driverClassName:
Because HikariCP has been used as the default DataSource implementation since Spring Boot 2, setting the application properties as above and running the application will configure a HikariDataSource bean based on those properties.
One advantage of HikariCP implementations is that they provide many configuration properties compared to other implementations, allowing detailed customization of database connection pooling behavior. Additional HikariDataSource properties can be set via the spring.datasource.hikari application properties as shown below.
spring:
datasource:
url:
username:
password:
driverClassName:
hikari:
connetionTimeout:
idleTimeout:
maxLifetime:
schema:
You can also build a DataSource instance directly using the DatasourceProperties class, which is the class that constructs the DataSource bean. After setting the database connection information in the application properties file, inject the property values into the fields of a DatasourceProperties instance using the @ConfigurationProperties annotation and create a DataSource bean by calling DatasourceProperties’s initializeDataSourceBuilder() method which returns a DataSourceBuilder.
spring:
datasource:
db:
url:
username:
password:
driverClassName:
public class DataSourceConfig {
@ConfigurationProperties("spring.datasource.db")
@Bean
public DatasourceProperties dbDatasourceProperties() {
return new DatasourceProperties();
}
@Bean
public DataSource dbDatasource() {
return dbDatasourceProperties()
.initializeDataSourceBuilder()
.build();
}
}
DatasourceProperties is an abstraction of DataSource properties and thus does not handle all implementation-specific properties. To configure a HikariDataSource bean and set all of its properties via the application properties file, either inject the auto-created HikariDataSource that Spring Boot generates from application properties, or manually configure the HikariDataSource bean using @ConfigurationProperties with HikariConfig.
spring:
datasource:
db:
jdbcUrl:
username:
password:
driverClassName:
schema:
@ConfigurationProperties("spring.datasource.db")
public class DbDataSourceConfiguration extends HikariConfig {
@Bean
public HikariDataSource dbDatasource() {
return new HikariDataSource(this);
}
}
Note that the JDBC URL field name is url for DataSourceProperties but jdbcUrl for HikariConfig, so the application property must use the correct field name for proper configuration.
If an application uses multiple databases, multiple DataSource beans must be configured for a multi-datasource setup. You can configure multiple DataSource beans based on application properties as follows.
spring:
datasource:
db1:
url:
username:
password:
driverClassName:
db2:
url:
username:
password:
driverClassName:
public class DataSourceConfig {
@ConfigurationProperties("spring.datasource.db1")
@Bean
public DatasourceProperties db1DatasourceProperties() {
return new DatasourceProperties();
}
@Bean
public DataSource db1Datasource() {
return db1DatasourceProperties()
.initializeDataSourceBuilder()
.build();
}
@ConfigurationProperties("spring.datasource.db2")
@Bean
public DatasourceProperties db2DatasourceProperties() {
return new DatasourceProperties();
}
@Bean
public DataSource db2Datasource() {
return db2DatasourceProperties()
.initializeDataSourceBuilder()
.build();
}
}
HikariDataSource bean auto-configuration in Spring Boot
Spring Boot’s HikariDataSource bean auto-configuration is performed based on the static Hikari inner class bean definition in DataSourceConfiguration. As indicated by the annotations on the Hikari static class, the HikariDataSource bean auto-configuration is performed only when a DataSource bean does not already exist. Therefore, manual configuration is required for multi-datasource setups.
The HikariDataSource auto-configuration uses @ConfigurationProperties to pass spring.datasource.hikari application properties into the bean definition and injects a DataSourceProperties bean which is populated from the spring.datasource application properties. Also, the initializeDataSourceBuilder() method of DataSourceProperties invoked during auto-configuration only sets the url, username, password, and driverClassName fields, so to set other HikariCP properties you must use spring.datasource.hikari application properties.
spring:
datasource:
url:
username:
password:
driverClassName:
hikari:
connetionTimeout:
idleTimeout:
maxLifetime:
schema:
Comments