[Spring Boot] usage example of Spring Boot + HikariCP connection pool

This page will introduce examples of Spring Boot and HikariCP.

HikariCP is a fast, simple, reliable and production ready JDBC connection pool.

In spring boot version 2.0, the default database connection pool technology has been switched from Tomcat pool to HikariCP.

This is because HikariCP provides excellent performance.

Now, since the release of Spring Boot 2.0, spring boot starter JDBC and spring boot starter data JPA solve the dependency of HikariCP by default, and the default value of spring.datasource.type attribute is HikariDataSource.

Spring boot first selects HikariCP, then Tomcat pool, and finally Commons DBCP2 (based on availability).

On this page, we will provide complete examples of HikariCP, Spring Boot data and MySQL.

We will create a demo application where we will perform create and read operations in the database.

We will configure HikariCP properties in the application.properties file, such as connectionTimeout, minimumIdle, maxPoolSize, idleTimeout, maxLifetime, and autoCommit.

Sample tool version

  1. Java 9
  2. Spring 5.0.7.RELEASE
  3. Spring Boot 2.0.3.RELEASE
  4. Maven 3.5.2
  5. MySQL 5.5
  6. Eclipse Oxygen

HikariCP dependency

Before using HikariCP, we need to ensure that we have solved the HikariCP dependency.

If we are using Maven, we can use the following dependencies.

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.1.0</version>
</dependency> 

If we are using Spring Boot 2.0 or later, we do not need to add HikariCP dependency in pom.xml or build.gradle, because spring boot starter JDBC and spring boot starter data JPA will solve it by default.

This means that if the dependency we use is

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency> 

perhaps

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.0.3.RELEASE</version>
</dependency> 

Then we don't need to include HikariCP dependencies in pom.xml or build.gradle.

HikariCP configuration

For the configuration of Hikari connection pool, we enable it by using spring.datasource.type and specifying the fully qualified name of the connection pool implementation in the application.properties file, as shown below.

spring.datasource.type = com.zaxxer.hikari.HikariDataSource 

If we use Spring Boot version 2.0 and later, Spring Boot will select HikariDataSource by default. We do not need to configure the above line.

Now to configure Hikari specific connection pool settings, Spring Boot provides the prefix spring.datasource.hikari. *, which can be used in the application.properties file.

We will discuss some frequently used configurations here.

1. connectionTimeout

connectionTimeout is the maximum number of milliseconds that a client waits for a connection from the connection pool. We need to configure it as follows.

spring.datasource.hikari.connection-timeout=20000 

2. minimumIdle

minimumIdle is the minimum number of free connections maintained by HikariCP in the connection pool. It is configured as follows.

spring.datasource.hikari.minimum-idle=5 

3. maximumPoolSize

maximumPoolSize configures the maximum number and size of connection pools. Its configuration method is as follows.

spring.datasource.hikari.maximum-pool-size=12 

4. idleTimeout

idleTimeout is the maximum time that a connection is allowed to idle in the connection pool, in milliseconds. Its configuration method is as follows.

spring.datasource.hikari.idle-timeout=300000 

5. maxLifetime

maxLifetime is the maximum lifetime (in milliseconds) after a connection in the pool is closed. Its configuration is shown below.

spring.datasource.hikari.max-lifetime=1200000 

The connection in use will never fail and will be deleted after the maximum lifetime only when it is closed.

6. autoCommit

autoCommit configures the default autoCommit behavior for connections returned from the pool. The default value is true.

spring.datasource.hikari.auto-commit=true 

Spring Boot Data + HikariCP + MySQL example

We will create a Spring Boot REST web service with Spring Boot Data, HikariCP and MySQL.

We will use CrudRepository to query the database.

We will also use RestTemplate to create a REST client to test our application.

First, find the project structure of the demo application.

Find the MySQL table structure used in our example.

MySQL Table: articles

CREATE TABLE `articles` (
	`article_id` INT(5) NOT NULL AUTO_INCREMENT,
	`title` VARCHAR(200) NOT NULL,
	`category` VARCHAR(100) NOT NULL,
	PRIMARY KEY (`article_id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB; 

Locate the Maven file to resolve the dependency issue.

pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-boot-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-boot-app</name>
	<description>Spring Boot Application</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.0.3.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>9</java.version>
	</properties>
	<dependencies>
	  <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-web</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-data-jpa</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>mysql</groupId>
		 <artifactId>mysql-connector-java</artifactId>
		 <version>6.0.5</version>
	  </dependency>	  
	  <!-- Spring Boot Data 2.0 includes HikariCP by default -->
          <!-- dependency>
                 <groupId>com.zaxxer</groupId>
                 <artifactId>HikariCP</artifactId>
                 <version>3.1.0</version>
          </dependency -->	  	  	  
	  <dependency>
		 <groupId>javax.xml.bind</groupId>
		 <artifactId>jaxb-api</artifactId>
		 <version>2.3.0</version>
	  </dependency>  	
          <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-devtools</artifactId>
                 <optional>true</optional>
          </dependency> 
	</dependencies>
	<build>
	  <plugins>
		 <plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		 </plugin>
	  </plugins>
	</build>
</project> 

If the Spring Boot version we use is lower than Spring Boot 2.0, we need to introduce the HikariCP dependency, as shown below.

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.1.0</version>
</dependency> 

HikariCP 3.1.0 is applicable to Java 8 and Java 9.

Now find the properties file to configure the data source and other properties.

The connection pool will be configured using HikariCP.

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=cp

#Spring Boot 2.0 includes HikariDataSource by default
#spring.datasource.type = com.zaxxer.hikari.HikariDataSource

spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=12
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
spring.datasource.hikari.auto-commit=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.format_sql=true 

If the Spring Boot version we use is lower than Spring Boot 2.0, we need to add the spring.datasource.type attribute for HikariCP, as shown below.

spring.datasource.type = com.zaxxer.hikari.HikariDataSource 

Now find the other files used in the demo.

ArticleRepository.java

package com.concretepage.repository;
import org.springframework.data.repository.CrudRepository;
import com.concretepage.entity.Article;

public interface ArticleRepository extends CrudRepository<Article, Long>  {
} 

Article.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private long articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public long getArticleId() {
		return articleId;
	}
	public void setArticleId(long articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
} 

IArticleService.java

package com.concretepage.service;
import java.util.List;
import com.concretepage.entity.Article;

public interface IArticleService {
     List<Article> getAllArticles();
     void addArticle(Article article);
} 

ArticleService.java

package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.entity.Article;
import com.concretepage.repository.ArticleRepository;

@Service
public class ArticleService implements IArticleService {
	@Autowired
	private ArticleRepository articleRepository;

	@Override
	public List<Article> getAllArticles(){
		List<Article> list = new ArrayList<>();
		articleRepository.findAll().forEach(e -> list.add(e));
		return list;
	}
	@Override
	public void addArticle(Article article){
    	articleRepository.save(article);
	}
} 

ArticleInfo.java

package com.concretepage.controller;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

public class ArticleInfo {
	@JsonInclude(Include.NON_NULL)
        private long articleId;
	@JsonInclude(Include.NON_NULL)
        private String title;
	@JsonInclude(Include.NON_NULL)
        private String category;
	public long getArticleId() {
		return articleId;
	}
	public void setArticleId(long articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	} 
} 

ArticleController.java

package com.concretepage.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;

@RestController
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;

	//Fetches all articles 
	@GetMapping(value= "articles")
	public ResponseEntity<List<ArticleInfo>> getAllArticles() {
		List<ArticleInfo> responseArticleList = new ArrayList<>();
		List<Article> articleList = articleService.getAllArticles();
		for (int i = 0; i < articleList.size(); i++) {
		    ArticleInfo ob = new ArticleInfo();
		    BeanUtils.copyProperties(articleList.get(i), ob);
		    responseArticleList.add(ob);    
		}
		return new ResponseEntity<List<ArticleInfo>>(responseArticleList, HttpStatus.OK);
	}
	
	//Creates a new article
	@PostMapping(value= "article")
	public ResponseEntity<Void> addArticle(@RequestBody ArticleInfo articleInfo, UriComponentsBuilder builder) {
		Article article = new Article();
		BeanUtils.copyProperties(articleInfo, article);
                articleService.addArticle(article);
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
} 

Now find the Main method of the Java class to run the application. To ensure that we are using HikariCP, we print the data source name.

SpringBootAppStarter.java

package com.concretepage;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppStarter implements CommandLineRunner {
    @Autowired
    DataSource dataSource;

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootAppStarter.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println("DataSource = " + dataSource);
    }
} 

When we start our application, we can see the following information in the console at the end of the server log.

output

DataSource = HikariDataSource (HikariPool-1) 

Now find the REST client to test the application.

RestClientUtil.java

package com.concretepage.client;
import java.net.URI;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.concretepage.entity.Article;

public class RestClientUtil {
    public void getAllArticlesDemo() {
	HttpHeaders headers = new HttpHeaders();
	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/articles";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class);
        Article[] articles = responseEntity.getBody();
        for(Article article : articles) {
              System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                      +", Category: "+article.getCategory());
        }
    }
    public void addArticleDemo() {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article";
	Article objArticle = new Article();
	objArticle.setTitle("Spring REST Security using Hibernate");
	objArticle.setCategory("Spring");
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        URI uri = restTemplate.postForLocation(url, requestEntity);
        System.out.println(uri.getPath());    	
    }
    public static void main(String args[]) {
    	RestClientUtil util = new RestClientUtil();
    	util.addArticleDemo();
    	util.getAllArticlesDemo();    	
    }    
} 

When we run the client, we will get the following output.

output

Id:1, Title:Spring REST Security using Hibernate, Category: Spring 

Test application

To test the application, first create a table in MySQL according to the method given in the article, and configure your database credentials in the application.properties file. Then, we can run REST network services in the following ways.

1. Use the Maven command

Download the source code of the project. Use the command prompt to go to the root folder of the project and run the command.

mvn spring-boot:run 

The Tomcat server will be started.

2. Use Eclipse

Use the download link at the end of the article to download the source code of the project. Import the project into eclipse. Using the command prompt, go to the root folder of the project and run.

mvn clean eclipse:eclipse 

Then refresh the project in eclipse. Click Run as - > java application to run the main class SpringBootAppStarter. The Tomcat server will be started.

3. Use executable jars

Using the command prompt, go to the root folder of the project and run the command.

mvn clean package 

We will get the executable JAR file spring-boot-app-0.0.1-SNAPSHOT.jar in the target folder. Run the JAR as follows.

java -jar target/spring-boot-app-0.0.1-SNAPSHOT.jar

The Tomcat server will be started.

Now we are ready to test the application. To run the Web service client, enter the RestClientUtil class in eclipse and click Run as - > java application.

reference

[1]Spring Boot Reference Guide
[2]HikariCP
[3]Spring Boot 2.0 Release Notes
[4]Spring Boot + HikariCP

Source download

spring-boot-hikaricp.zip

Tags: Java Spring Spring Boot HiKariCP

Posted on Fri, 24 Sep 2021 04:10:17 -0400 by web.designer.iq