Spring Boot applications often struggle with database connection management, leading to performance bottlenecks and application instability under load.
Let’s see HikariCP in action. Imagine a web application with a /users endpoint that fetches user data.
@RestController
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping
public List<User> getAllUsers() {
// This simple call might involve multiple DB round trips depending on User entity relationships
return userRepository.findAll();
}
}
When a request hits /users, Spring Boot uses the configured DataSource (backed by HikariCP) to get a Connection. This Connection is then used by the JPA UserRepository to execute SQL queries. After the operation, the Connection is returned to the pool.
The core problem HikariCP solves is efficiently managing these database Connections. Instead of establishing a new Connection for every database operation (which is extremely slow and resource-intensive), HikariCP maintains a pool of ready-to-use Connections. When a request needs a Connection, it borrows one from the pool. When done, it returns it. This dramatically reduces latency and the overhead on the database server.
Here’s how you configure it in application.properties (or application.yml):
spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver
# HikariCP specific properties
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.pool-name=MyAppHikariPool
maximum-pool-size: This is the absolute maximum number of connections HikariCP will create. Setting this too high can overwhelm your database. Setting it too low can starve your application under load. A common starting point for a moderately busy application is 10-50.
minimum-idle: This is the minimum number of idle connections HikariCP will try to maintain in the pool. If the number of idle connections drops below this, HikariCP will try to create new ones. This helps ensure connections are readily available when traffic spikes. A good rule of thumb is 2-10.
connection-timeout: The maximum time (in milliseconds) that a client will wait for a connection from the pool. If the pool is exhausted and no connection becomes available within this time, an exception is thrown. 30 seconds (30000ms) is a reasonable default, but you might decrease it to 5-10 seconds (5000-10000ms) if you want to fail faster during high load.
idle-timeout: The maximum time (in milliseconds) that a connection is allowed to sit idle in the pool. If a connection is not borrowed from the pool for longer than this, it will be retired (closed) by HikariCP. This prevents stale connections from accumulating, especially if your max-lifetime is very long. 10 minutes (600000ms) is a common value.
max-lifetime: The maximum lifetime (in milliseconds) of a connection in the pool. After this time, the connection will be retired and replaced. This is crucial for preventing issues with database or network infrastructure that might drop connections after a certain period of inactivity, or to ensure connections are refreshed periodically. 30 minutes (1800000ms) is a common setting.
pool-name: A descriptive name for your connection pool. This is useful for logging and monitoring, helping to distinguish between different pools if you have multiple data sources.
The pool-name is not just for display; it’s used in HikariCP’s internal metrics, which you can expose via Spring Boot Actuator. This allows you to monitor pool health in real-time. For example, you can scrape metrics like hikaricp.connections.active and hikaricp.connections.idle using Prometheus.
A common pitfall is setting maximum-pool-size too high, leading to OutOfMemoryError on the database server or connection exhaustion. Conversely, setting maximum-pool-size too low will lead to threads waiting for connections, increasing request latency and potentially causing cascading failures. The optimal value depends heavily on your application’s concurrency, typical request duration, and database capacity. A good strategy is to start with a conservative maximum-pool-size (e.g., 10) and gradually increase it while monitoring your application and database performance, looking for signs of connection contention or resource exhaustion.
When you tune these parameters, you’re not just adjusting numbers; you’re directly influencing the trade-off between resource utilization on your application server and your database, and the responsiveness of your application under varying loads.
The next logical step after tuning the HikariCP pool itself is understanding how to monitor its behavior effectively in production.