1. Overview

Spring Boot is an opinionated – yet powerful – layer of abstraction placed on top of a plain Spring platform, which makes developing stand-alone and web applications a no-brainer. Spring Boot provides a few handy “starter” dependencies, aimed at running and testing Java applications with a minimal footprint.

One key component of these starter dependencies is spring-boot-starter-data-jpa. This allows us to use JPA and work with production databases by using some popular JDBC connection pooling implementations, such as HikariCP and Tomcat JDBC Connection Pool.

In this tutorial, we’ll learn how to configure a Tomcat connection pool in Spring Boot.

2. The Maven Dependencies

Spring Boot uses HikariCP as the default connection pool, due to its remarkable performance and enterprise-ready features.

Here’s how Spring Boot automatically configures a connection pool datasource:

  1. Spring Boot will look for HikariCP on the classpath and use it by default when present
  2. If HikariCP is not found on the classpath, then Spring Boot will pick up the Tomcat JDBC Connection Pool, if it’s available
  3. If neither of these options is available, Spring Boot will choose Apache Commons DBCP2, if that is available

To configure a Tomcat JDBC connection pool instead of the default HikariCP, we’ll exclude HikariCP from the spring-boot-starter-data-jpa dependency and add the tomcat-jdbc Maven dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jdbc</artifactId>
    <version>10.1.7</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.214</version>
    <scope>runtime</scope>
</dependency>

This simple approach allows us to get Spring Boot using a Tomcat connection pool without having to write a @Configuration class and programmatically define a DataSource bean.

It’s also worth noting that in this case, we’re using the H2 in-memory database. Spring Boot will autoconfigure H2 for us, without having to specify a database URL, user, and password.

We just need to include the corresponding dependency in the “pom.xml” file and Spring Boot will do the rest for us.

Alternatively, it’s possible to skip the connection pool scanning algorithm that Spring Boot uses and explicitly specify a connection pooling datasource in the “application.properties” file*,* using the “spring.datasource.type” property:

spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
// other spring datasource properties

3. Tweaking the Connection Pool With the “application.properties” File

Once we’ve successfully configured a Tomcat connection pool in Spring Boot, it’s very likely that we’ll want to set up some additional properties, for optimizing its performance and suiting some specific requirements.

We can do so in the “application.properties” file:

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   

Please notice that we’ve configured a few additional connection pooling properties, such as the pool’s initial size, and the maximum and minimum number of idle connections.

We can also specify some Hibernate-specific properties:

# Hibernate specific properties
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false

4. Testing the Connection Pool

Let’s write a simple integration test to check that Spring Boot has correctly configured the connection pool:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootTomcatConnectionPoolIntegrationTest {
    
    @Autowired
    private DataSource dataSource;
    
    @Test
    public void givenTomcatConnectionPoolInstance_whenCheckedPoolClassName_thenCorrect() {
        assertThat(dataSource.getClass().getName())
          .isEqualTo("org.apache.tomcat.jdbc.pool.DataSource");
    }
}

5. A Sample Command Line Application

With all the connection pooling plumbing already set, let’s build a simple command line application.

In doing so, we can see how to perform some CRUD operations on an H2 database using the powerful DAO layer that Spring Data JPA (and transitively, Spring Boot) provides out of the box.

For a detailed guide on how to get started using Spring Data JPA, please check this article.

5.1. The Customer Entity Class

Let’s first define a naive Customer entity class:

@Entity
@Table(name = "customers")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(name = "first_name")
    private String firstName;
    
    // standard constructors / getters / setters / toString
}

5.2. The CustomerRepository Interface

In this case, we just want to perform CRUD operations on a few Customer entities**.** Additionally, we need to fetch all the customers that match a given last name.

So, all that we have to do is to extend Spring Data JPA’s CrudRepository interface and define a tailored method:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
    List<Customer> findByLastName(String lastName);
}

Now we can easily fetch a Customer entity by its last name.

5.3. The CommandLineRunner Implementation

Finally, we need at least to persist a few Customer entities in the database and verify that our Tomcat connection pool is actually working.

Let’s create an implementation of Spring Boot’s CommandLineRunner interface. Spring Boot will bootstrap the implementation before launching the application:

public class CommandLineCrudRunner implements CommandLineRunner {
    
    private static final Logger logger = LoggerFactory.getLogger(CommandLineCrudRunner.class);
    
    @Autowired
    private final CustomerRepository repository;
    
    public void run(String... args) throws Exception {
        repository.save(new Customer("John", "Doe"));
        repository.save(new Customer("Jennifer", "Wilson"));
        
        logger.info("Customers found with findAll():");
        repository.findAll().forEach(c -> logger.info(c.toString()));
        
        logger.info("Customer found with findById(1L):");
        Customer customer = repository.findById(1L)
          .orElseGet(() -> new Customer("Non-existing customer", ""));
        logger.info(customer.toString());
        
        logger.info("Customer found with findByLastName('Wilson'):");
        repository.findByLastName("Wilson").forEach(c -> {
            logger.info(c.toString());
        });
    }
}

In a nutshell, the CommandLineCrudRunner class first saves a couple of Customer entities in the database. Next, it fetches the first one using the findById() method. Finally, it retrieves a customer with the findByLastName() method.

5.4. Running the Spring Boot Application

Of course, the last thing that we need to do is just run the sample application. Then we can see the Spring Boot/Tomcat connection pool tandem in action:

@SpringBootApplication
public class SpringBootConsoleApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SpringBootConsoleApplication.class);
    }
}

6. Conclusion

In this tutorial, we learned how to configure and use a Tomcat connection pool in Spring Boot. In addition, we developed a basic command line application to show how easy is to work with Spring Boot, a Tomcat connection pool, and the H2 database.

As usual, all the code samples shown in this tutorial are available over on GitHub.