Spring Boot HikariCP Connection Pool Tutorial

Watch on YouTube

Spring Boot Hikari Connection Pool

What is a database connection pool?

A database connection pool is a managed collection of reusable database connections. Instead of opening a new connection for every HTTP request, a Spring Boot application borrows an available connection, runs the database operation, and returns the connection to the pool.

Spring Boot uses HikariCP as its default JDBC connection pool when the application uses Spring JDBC or Spring Data JPA. HikariCP is lightweight, fast, and designed for reliable connection management.

Why is a connection pool important?

1. Efficient resource management

Creating a database connection involves network communication, authentication, session setup, and database-side resources. Recreating a connection for every request adds unnecessary overhead.

A pool creates and reuses connections, which reduces the cost of repeatedly opening and closing database sessions.

2. Better application performance

Because connections are already available, requests spend less time waiting for database setup. A pool also supports concurrent requests by managing multiple connections safely.

3. Controlled database usage

The maximum pool size limits how many connections an application can use at the same time. This prevents a busy application from opening an uncontrolled number of connections and overwhelming the database server.

Idle connections can also be removed after a configured period, allowing unused resources to be released.

4. Improved reliability

HikariCP validates and replaces connections that are closed, expired, or no longer usable. Connection timeouts also prevent requests from waiting forever when the pool has no available connection.

5. Easier scalability

Connection pooling helps an application handle more concurrent requests efficiently. However, pool size must be planned across all application instances so the combined number of connections stays within the database server’s limits.

Does Spring Data JPA include HikariCP?

In a standard Spring Boot application, you usually do not need to add a separate HikariCP dependency. HikariCP is brought in by the Spring Boot JDBC or Spring Data JPA starter and is selected automatically when it is available.

You still need to add the JDBC driver for your database. The following Maven dependencies create a simple Spring Boot REST application that uses JPA with MySQL:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.0</version>
    <relativePath/>
  </parent>
  <groupId>com.example</groupId>
  <artifactId>student</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>student</name>
  <description>Spring Boot HikariCP demonstration</description>
  <properties><java.version>17</java.version></properties>
  <dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

Example Spring Boot application

The following example exposes basic student endpoints. When the repository accesses MySQL, the datasource obtains connections from HikariCP automatically.

Entity

package com.example.student.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String course;

    // Constructors, getters, and setters omitted for brevity
}

Repository

package com.example.student.repository;

import com.example.student.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, Long> {
}

Service

package com.example.student.service;

import com.example.student.entity.Student;
import com.example.student.repository.StudentRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentService {
    private final StudentRepository studentRepository;

    public StudentService(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    public List<Student> findAll() {
        return studentRepository.findAll();
    }

    public Student save(Student student) {
        return studentRepository.save(student);
    }
}

Controller

package com.example.student.controller;

import com.example.student.entity.Student;
import com.example.student.service.StudentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/students")
public class StudentController {
    private final StudentService studentService;

    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }

    @GetMapping
    public List<Student> findAll() {
        return studentService.findAll();
    }

    @PostMapping
    public Student create(@RequestBody Student student) {
        return studentService.save(student);
    }
}

Configure MySQL and HikariCP

Add the datasource and HikariCP settings to src/main/resources/application.properties:

spring.application.name=student
server.port=9090

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=your-password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# HikariCP settings
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.pool-name=StudentHikariPool
spring.datasource.hikari.max-lifetime=600000

Important HikariCP properties

PropertyDescription
connection-timeoutMaximum time, in milliseconds, that a request waits for a connection.
maximum-pool-sizeMaximum number of connections in the pool.
minimum-idleMinimum number of idle connections maintained by the pool.
idle-timeoutMaximum time an unused connection can remain idle.
max-lifetimeMaximum lifetime of a connection before HikariCP replaces it.
pool-nameName shown in logs and monitoring tools.

How should you choose the pool size?

A larger pool does not automatically improve performance. Each active connection consumes memory and database resources. Start with a reasonable value, measure application behavior, and adjust the pool after reviewing metrics.

Consider the database connection limit, the number of application instances, average query duration, and the number of concurrent requests. For example, ten connections per instance across five instances can consume up to fifty database connections.

Enable HikariCP logging

Temporary debug logging can help verify the configured pool and investigate connection problems:

logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
logging.level.com.zaxxer.hikari=TRACE

Use TRACE logging carefully because it can generate a large amount of output. Disable it or reduce it after troubleshooting.

Monitor the connection pool with Actuator

Spring Boot Actuator can expose datasource metrics such as active connections, idle connections, pending requests, and connection timeouts. Expose only the endpoints required by your environment and protect operational endpoints.

management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=when-authorized

Test connection-pool behavior with JMeter

JMeter can simulate concurrent requests and help you observe how the application behaves when many users access the database at the same time.

Step 1: Install JMeter

Download JMeter from the official Apache JMeter website, extract the archive, and start jmeter.bat on Windows or jmeter on Linux and macOS.

Step 2: Create a thread group

Create a Thread Group under a new Test Plan. As a starting example, configure:

  • Number of threads: 100
  • Ramp-up period: 10 seconds
  • Loop count: 10

Step 3: Add an HTTP Request

Add an HTTP Request sampler for the student endpoint:

  • Server: localhost
  • Port: 9090
  • Method: GET
  • Path: /students

Step 4: Add a listener and run the test

Add a Summary Report or View Results in Table listener, start the Spring Boot application, and run the test plan. Review response time, throughput, errors, and connection-pool metrics together. A slow response time does not always indicate a pool problem; queries, database indexes, network latency, and application code can also be responsible.

HikariCP best practices

  • Use Spring-managed repositories and transactions so connections are returned reliably.
  • Do not create a new datasource or connection for every request.
  • Keep database credentials outside source control and use environment-specific configuration.
  • Set a connection timeout so requests fail clearly instead of waiting indefinitely.
  • Monitor active, idle, pending, and timeout metrics in production.
  • Configure the pool according to the database limits and the number of application instances.

Continue learning