Spring Boot Tomcat Connection Pool
June 19, 2018
This page will walk through Spring Boot Tomcat JDBC connection pool example. Tomcat connection pool supports for highly concurrent environments with high performance. Tomcat connection pool is extremely simple because of its very simplified implementation. Tomcat connection pool has ability to configure custom interceptors, better idle connection handling and performs asynchronous connection retrieval. In Spring Boot 1.x, Tomcat connection pool was the default connection pool but in Spring Boot 2.x HikariCP is the default connection pool. Here on this page we will provide complete example of Tomcat JDBC connection pool with Spring Boot Data and MySQL. We will create a demo application in which we will perform create and read operation in database. We will configure Tomcat connection pool properties for example initialSize, maxWait, maxActive, maxIdle, minIdle, defaultAutoCommit and testOnBorrow in application.properties
file.
Contents
Technologies Used
Find the technologies being used in our example.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
Tomcat JDBC Dependency
Before using Tomcat connection pool, we need to make sure that we have resolved the Tomcat JDBC dependency. If we are using Maven we can use following dependency.<dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>9.0.8</version> </dependency>
tomcat-jdbc
is used with either spring-boot-starter-data-jpa
or spring-boot-starter-jdbc
. To resolve spring-boot-starter-data-jpa
we can use Maven dependency as given below.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
spring-boot-starter-jdbc
, use Maven dependency as given below.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
tomcat-jdbc
in pom.xml
or build.gradle
ourselves because spring-boot-starter-jdbc
and spring-boot-starter-data-jpa
resolve it by default.
Tomcat Connection Pool Configurations
For the Tomcat connection pool configuration, we enable it by usingspring.datasource.type
and assigning it fully qualified name of the Tomcat connection pool implementation in application.properties
file as following.
spring.datasource.type = org.apache.tomcat.jdbc.pool.DataSource
Now to configure Tomcat specific connection pool settings, Spring Boot provides
spring.datasource.tomcat.*
prefix to be used in application.properties
file. We will discuss here some frequently used configurations.
1. initialSize
initialSize
is the initial number of connections that are created when the pool is started. It is configured as following.
spring.datasource.tomcat.initial-size=15
maxWait
is the maximum number of milliseconds that a pool will wait to return a connection before throwing an exception. It is configured as following.
spring.datasource.tomcat.max-wait=20000
maxActive
is the maximum number of active connections that the pool can allocate at the same time. It is configured as following.
spring.datasource.tomcat.max-active=50
maxIdle
is the maximum number of connections that should be kept in the pool at all times. It is configured as following.
spring.datasource.tomcat.max-idle=15
minIdle
is the minimum number of connections that should be kept in the pool at all times. It is configured as following.
spring.datasource.tomcat.min-idle=8
defaultAutoCommit
property configures the default auto-commit state of connections created by this pool. It is boolean and default value is true.
spring.datasource.tomcat.default-auto-commit=true
testOnBorrow
is the boolean value that indicates whether objects will be validated before being borrowed from the pool. Default is false.
spring.datasource.tomcat.test-on-borrow=false
Spring Boot Data + Tomcat JDBC Connection Pool + MySQL Example
We will create a Spring Boot REST web service with Spring Boot Data, Tomcat JDBC Connection Pool and MySQL. We will useCrudRepository
to query database. We will also create a REST client using RestTemplate
to test our application. First find the project structure of the demo application.

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;
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> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>9.0.8</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>
spring.datasource.url=jdbc:mysql://localhost:3306/concretepage spring.datasource.username=root spring.datasource.password=cp spring.datasource.type = org.apache.tomcat.jdbc.pool.DataSource spring.datasource.tomcat.initial-size=15 spring.datasource.tomcat.max-wait=20000 spring.datasource.tomcat.max-active=50 spring.datasource.tomcat.max-idle=15 spring.datasource.tomcat.min-idle=8 spring.datasource.tomcat.default-auto-commit=true spring.datasource.tomcat.test-on-borrow=false 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
package com.concretepage.repository; import org.springframework.data.repository.CrudRepository; import com.concretepage.entity.Article; public interface ArticleRepository extends CrudRepository<Article, Long> { }
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; } }
package com.concretepage.service; import java.util.List; import com.concretepage.entity.Article; public interface IArticleService { List<Article> getAllArticles(); void addArticle(Article article); }
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); } }
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; } }
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); } }
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); } }
Output
DataSource = org.apache.tomcat.jdbc.pool.DataSource@5437ca1b{ConnectionPool[defaultAutoCommit=true; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=50; maxIdle=15; minIdle=8; initialSize=15; maxWait=20000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=********; url=jdbc:mysql://localhost:3306/concretepage; username=root; validationQuery=/* ping */ SELECT 1; validationQueryTimeout=-1; validatorClassName=null; validationInterval=3000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; ignoreExceptionOnPreLoad=false; useStatementFacade=true; }
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(); } }
Output
Id:1, Title:Spring REST Security using Hibernate, Category: Spring
Test Application
To test the application, first create table in MySQL as given in the article and configure your database credentials inapplication.properties
file. Then we can run REST web service in following ways.
1. Using Maven Command: Download the project source code. Go to the root folder of the project using command prompt and run the command.
mvn spring-boot:run
2. Using Eclipse: Download the project source code using the download link given at the end of article. Import the project into eclipse. Using command prompt, go to the root folder of the project and run.
mvn clean eclipse:eclipse
SpringBootAppStarter
by clicking Run as -> Java Application. Tomcat server will be started.
3. Using Executable JAR: Using command prompt, go to the root folder of the project and run the command.
mvn clean package
java -jar target/spring-boot-app-0.0.1-SNAPSHOT.jar
Now we are ready to test the application. To run web service client, go to the
RestClientUtil
class in eclipse and click on Run as -> Java Application.
References
Spring Boot Reference GuideTomcat JDBC Connection Pool