1. 概述

Spring Boot 是一个基于普通 Spring 平台的、带有一定“主观倾向”但功能强大的抽象层,它极大地简化了独立应用和 Web 应用的开发流程。Spring Boot 提供了一些非常实用的 “starter” 依赖项,可以让我们以最小的配置运行和测试 Java 应用。

其中一个重要组件是 **spring-boot-starter-data-jpa**,它使我们可以使用 JPA 来操作生产数据库,并支持多种流行的 JDBC 连接池实现,比如 HikariCPTomcat JDBC Connection Pool

在本教程中,我们将学习如何在 Spring Boot 中配置并使用 Tomcat JDBC 连接池

2. Maven 依赖配置

默认情况下,Spring Boot 使用 HikariCP 作为连接池,因为它的性能表现优异且具备企业级特性。

✅ Spring Boot 自动配置连接池数据源的逻辑如下:

  1. 如果 classpath 中存在 HikariCP,则优先使用它;
  2. 如果没有 HikariCP,但有 Tomcat JDBC 连接池,则会自动选用;
  3. 如果两者都没有,则尝试使用 Apache Commons DBCP2(如果可用);

如果我们想使用 Tomcat JDBC 连接池而不是默认的 HikariCP,可以通过以下方式操作:

  • spring-boot-starter-data-jpa 中排除 HikariCP;
  • 添加 [tomcat-jdbc](https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jdbc/9.0.11/jar) 依赖;

示例 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>

⚠️ 注意:我们这里使用的是 H2 内存数据库,Spring Boot 会自动帮我们配置好,无需手动指定 URL、用户名或密码。

✅ 另一种方式:显式指定连接池类型

你也可以跳过 Spring Boot 的自动扫描机制,在 application.properties 文件中通过 spring.datasource.type 显式指定连接池类型:

spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
// 其他 datasource 配置...

3. 使用 application.properties 调整连接池参数

一旦成功配置了 Tomcat 连接池,通常还需要根据实际业务场景进行一些性能调优和参数设置。

application.properties 中添加如下配置即可:

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   

上面这些配置项包括:

  • 初始连接数;
  • 获取连接的最大等待时间;
  • 最大活跃连接数;
  • 最大空闲连接数;
  • 最小空闲连接数;
  • 是否开启自动提交;

此外,还可以配置一些 Hibernate 特定的属性:

# 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. 测试连接池是否生效

我们可以编写一个简单的集成测试来验证 Spring Boot 是否正确加载了 Tomcat 连接池:

@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");
    }
}

这个测试确保我们使用的确实是 Tomcat 的连接池实现。

5. 示例命令行应用

现在我们已经完成了连接池的基础配置,接下来构建一个简单的命令行应用来演示如何结合 Spring Data JPA 和 Tomcat 连接池对 H2 数据库执行 CRUD 操作。

5.1. Customer 实体类

首先定义一个简单的实体类:

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(name = "first_name")
    private String firstName;
    
    // 标准构造函数 / getter / setter / toString
}

5.2. CustomerRepository 接口

我们只需要继承 Spring Data JPA 的 CrudRepository 接口,并自定义一个按姓氏查找的方法:

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

这样就能轻松实现按姓氏查询客户的功能。

5.3. CommandLineRunner 实现

最后创建一个 CommandLineRunner 实现类,在应用启动时执行一些数据库操作:

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());
        });
    }
}

这段代码主要做了以下几件事:

  1. 插入两条客户记录;
  2. 查询所有客户;
  3. 根据 ID 查询单个客户;
  4. 根据姓氏查询客户;

5.4. 启动 Spring Boot 应用

最后,我们只需要一个标准的 Spring Boot 主类来启动整个程序:

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

运行后你会看到 Tomcat 连接池配合 Spring Boot 正常工作的日志输出。

6. 总结

在本教程中,我们详细介绍了如何在 Spring Boot 中配置并使用 Tomcat JDBC 连接池,并通过一个简单的命令行应用展示了其与 H2 数据库配合使用的便捷性。

一如既往,本文中的所有代码都可以在 GitHub 仓库 中找到。


原始标题:Configuring a Tomcat Connection Pool in Spring Boot