一、核心概念

在 Spring Boot 中,数据源 (DataSource) 是应用程序连接和操作数据库的桥梁。它封装了数据库连接池、连接参数、认证信息等。Spring Boot 的 自动配置 (Auto-configuration) 机制会根据类路径上的依赖(如 spring-boot-starter-jdbcspring-boot-starter-data-jpa)和 application.properties (或 application.yml) 中的配置,自动创建并配置一个 DataSource Bean。

1. 核心组件

  • DataSource: Java 标准接口 (javax.sql.DataSource),负责提供数据库连接 (Connection)。Spring Boot 通常会自动配置一个连接池实现。
  • 连接池 (Connection Pool): 管理数据库连接的生命周期,复用连接,避免频繁创建和销毁连接带来的性能开销。常见的实现:
    • HikariCP: Spring Boot 2.x+ 的默认连接池,性能优异,配置简单。
    • Tomcat JDBC Pool: Spring Boot 1.x 的默认池。
    • Commons DBCP2: Apache 的连接池。
  • JDBC URL: 连接数据库的地址,包含协议、主机、端口、数据库名等信息。
  • 驱动类 (Driver Class): JDBC 驱动,负责与特定数据库通信。Spring Boot 通常能根据 JDBC URL 自动推断。

2. 配置文件 (application.properties)

  • 位于 src/main/resources 目录下。
  • 键值对格式:key=value
  • Spring Boot 启动时会加载此文件,并根据其中的属性配置应用。

3. 自动配置原理

  1. 检测到 spring-boot-starter-jdbcspring-boot-starter-data-jpa 等依赖。
  2. 检查 application.properties 中是否配置了 spring.datasource.* 属性。
  3. 如果配置了必要属性(如 url, username, password),则自动创建 DataSource Bean。
  4. 如果类路径有 HikariCP,则使用 HikariDataSource;否则尝试其他池。

二、操作步骤(非常详细)

步骤 1:添加必要的依赖

pom.xml (Maven) 或 build.gradle (Gradle) 中添加:

Maven (pom.xml)

<dependencies>
    <!-- Spring Boot Starter for JDBC (会自动包含数据源自动配置) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <!-- 或者使用 JPA (会包含 JDBC) -->
    <!--
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    -->

    <!-- 数据库驱动 (以 MySQL 8 为例) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope> <!-- 通常设为 runtime -->
    </dependency>

    <!-- HikariCP (Spring Boot 2+ 默认,通常无需显式添加,除非要指定版本) -->
    <!--
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
    -->
</dependencies>

Gradle (build.gradle)

dependencies {
    // Spring Boot Starter for JDBC
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'

    // Or use JPA
    // implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    // Database Driver (MySQL 8)
    runtimeOnly 'mysql:mysql-connector-java'

    // HikariCP (usually included by default)
    // implementation 'com.zaxxer:HikariCP'
}

步骤 2:配置 application.properties

src/main/resources/application.properties 文件中添加数据库配置。

2.1 基本配置 (必需)

# --- 数据源基本配置 ---
# JDBC URL (连接地址)
# 格式: jdbc:mysql://[host]:[port]/[database]?[parameters]
# 注意: useSSL=false 仅用于开发环境,生产应配置正确SSL
# serverTimezone=UTC 或 你所在时区 (如 Asia/Shanghai),避免时区问题
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC

# 数据库用户名
spring.datasource.username=myuser

# 数据库密码
spring.datasource.password=mypassword

# 驱动类名 (Spring Boot 通常能自动推断,可省略)
# spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.2 HikariCP 连接池配置 (推荐优化)

# --- HikariCP 连接池配置 (spring.datasource.hikari.*) ---
# 连接池名称 (日志和监控中可见)
spring.datasource.hikari.pool-name=MyHikariCP

# 连接池最小空闲连接数
spring.datasource.hikari.minimum-idle=5

# 连接池最大连接数 (重要!根据数据库和应用负载调整)
spring.datasource.hikari.maximum-pool-size=20

# 连接超时时间 (毫秒) - 获取连接的最长等待时间
spring.datasource.hikari.connection-timeout=20000

# 连接最大存活时间 (毫秒) - 连接在池中最大存活时间,到期会被关闭
# 设为较小值有助于应对数据库重启等情况
spring.datasource.hikari.max-lifetime=1800000

# 连接空闲超时时间 (毫秒) - 连接在池中空闲多久后被回收
spring.datasource.hikari.idle-timeout=600000

# 测试连接的SQL查询 (HikariCP 通常能自动检测,可省略或根据数据库设置)
# MySQL
spring.datasource.hikari.connection-test-query=SELECT 1
# PostgreSQL
# spring.datasource.hikari.connection-test-query=SELECT 1
# Oracle
# spring.datasource.hikari.connection-test-query=SELECT 1 FROM DUAL

2.3 其他数据库示例

PostgreSQL:

spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=mypassword
# driver-class-name usually not needed
# spring.datasource.driver-class-name=org.postgresql.Driver

H2 (内存数据库,常用于测试):

# 内存模式
spring.datasource.url=jdbc:h2:mem:testdb
# 或 文件模式
# spring.datasource.url=jdbc:h2:~/testdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

步骤 3:验证数据源配置

3.1 使用 DataSource Bean

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@RestController
public class DataSourceTestController {

    @Autowired
    private DataSource dataSource; // Spring Boot 自动配置的 DataSource

    @Autowired
    private JdbcTemplate jdbcTemplate; // 通常更方便

    @GetMapping("/test-datasource")
    public String testDataSource() {
        try (Connection connection = dataSource.getConnection()) {
            if (connection != null && !connection.isClosed()) {
                String dbName = connection.getCatalog(); // 获取数据库名
                return "Connected to database: " + dbName + " using " + 
                       dataSource.getClass().getSimpleName();
            }
        } catch (SQLException e) {
            return "Connection failed: " + e.getMessage();
        }
        return "Unknown connection state";
    }

    @GetMapping("/test-jdbc")
    public String testJdbc() {
        // 使用 JdbcTemplate 执行简单查询
        Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
        return "User count: " + count;
    }
}

3.2 启动应用并访问端点

启动 Spring Boot 应用,访问 http://localhost:8080/test-datasource,应看到成功连接的信息。


三、常见错误与解决方案

错误 原因 解决方案
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver MySQL 驱动未添加或版本冲突 检查 pom.xml/build.gradle 是否添加了正确的 mysql-connector-java 依赖。确保版本与 MySQL 服务器兼容。
Access denied for user 'myuser'@'localhost' 用户名或密码错误 检查 application.properties 中的 usernamepassword 是否正确。确认数据库用户有连接权限。
Unknown database 'mydb' 数据库不存在 在数据库管理工具中创建指定的数据库 (CREATE DATABASE mydb;)。
Communications link failure / Connection refused 数据库服务未启动或端口错误 确认数据库服务(如 MySQL, PostgreSQL)正在运行。检查 application.properties 中的 hostport 是否正确。
The server time zone value '...' is unrecognized 时区配置问题 (常见于 MySQL) 在 JDBC URL 中添加 serverTimezone=UTCserverTimezone=Asia/Shanghai 等有效时区。
HikariPool-1 - Exception during pool initialization 连接池初始化失败 检查上述所有连接问题。确认网络可达。检查连接池参数(如 maximum-pool-size)是否合理。
No qualifying bean of type 'javax.sql.DataSource' available 数据源未配置或自动配置未触发 确保添加了 spring-boot-starter-jdbcspring-boot-starter-data-jpa 依赖。检查 application.properties 文件位置和拼写。确认配置了 spring.datasource.url 等必需属性。

四、注意事项

  1. 密码安全application.properties 中的密码是明文的。生产环境切勿直接存放明文密码。应使用:
    • 环境变量 (SPRING_DATASOURCE_PASSWORD)
    • 配置中心 (如 Spring Cloud Config, Consul, Zookeeper)
    • 云平台密钥管理服务 (如 AWS Secrets Manager, Azure Key Vault)
    • 命令行参数 (--spring.datasource.password=mypassword)
  2. JDBC URL 参数:不同的数据库和驱动可能需要特定的连接参数(如 useSSL, serverTimezone, allowPublicKeyRetrieval for MySQL 8)。查阅对应数据库驱动的文档。
  3. 驱动类名:Spring Boot 能根据 spring.datasource.url 的协议(jdbc:mysql, jdbc:postgresql)自动推断驱动类。通常可以省略 spring.datasource.driver-class-name。如果自动推断失败再手动指定。
  4. 连接池选择:优先使用 HikariCP(Spring Boot 默认),性能最好。除非有特殊需求,否则无需更换。
  5. 属性前缀:HikariCP 的配置必须以 spring.datasource.hikari. 开头。其他连接池(如 Tomcat)使用 spring.datasource.tomcat.*
  6. 多数据源application.properties 默认只配置一个主数据源。配置多个数据源需要更复杂的 @Configuration 类和 @Primary 注解。

五、使用技巧

  1. 使用环境变量覆盖:在部署时,通过环境变量覆盖 application.properties 中的敏感信息或环境特定配置。
    export SPRING_DATASOURCE_URL=jdbc:mysql://prod-db-host:3306/proddb
    export SPRING_DATASOURCE_USERNAME=produser
    export SPRING_DATASOURCE_PASSWORD=prodsecret
    java -jar myapp.jar
    
  2. 配置文件分 profile:使用 application-dev.properties, application-prod.properties 等,通过 spring.profiles.active=dev 激活不同环境的配置。
  3. HikariCP 监控:HikariCP 提供了 JMX MBean,可以监控连接池状态(活跃连接、空闲连接、等待线程等)。可通过 JConsole 或集成 Prometheus + Grafana 监控。
  4. JdbcTemplate / NamedParameterJdbcTemplate:直接使用 DataSource 较底层,推荐使用 JdbcTemplate 简化 JDBC 操作。
  5. DataSourceBuilder:在需要编程式创建 DataSource 时(如多数据源),可使用 DataSourceBuilder
  6. 健康检查:Spring Boot Actuator 的 /actuator/health 端点会检查数据源连接状态。

六、最佳实践

  1. 使用连接池必须使用连接池(如 HikariCP),绝不能使用 DriverManagerDataSource(无池化,性能极差)。
  2. 合理设置连接池大小
    • maximum-pool-size: 根据数据库最大连接数、应用并发量、服务器资源估算。通常从 10-20 开始,根据监控调整。避免过大,耗尽数据库连接或内存。
    • minimum-idle: 保持一定数量的空闲连接,减少获取新连接的延迟。通常设为与 maximum-pool-size 相同或略小。
  3. 设置超时时间
    • connection-timeout: 避免请求无限等待连接。设置合理值(如 20s)。
    • max-lifetime: 防止连接过长导致问题(如数据库重启后连接失效)。通常设为几分钟到几十分钟。
    • idle-timeout: 回收长时间不用的连接。
  4. 生产环境使用安全配置绝对不要在代码仓库中存放生产数据库的明文密码。使用环境变量、配置中心或密钥管理服务。
  5. 配置正确的时区:在 JDBC URL 中明确指定 serverTimezone,避免日期时间数据错乱。
  6. 启用 SSL (生产环境):在生产环境中,如果网络不可信,应配置数据库连接的 SSL/TLS 加密。
  7. 监控连接池:集成监控工具,持续观察连接池的活跃度、等待队列等指标,及时发现性能瓶颈。
  8. 使用 JPA/Hibernate 或 MyBatis:对于复杂的 ORM 操作,优先考虑使用 JPA/Hibernate 或 MyBatis 等框架,而不是直接使用 JdbcTemplate

七、性能优化

  1. 选择 HikariCP:它是目前性能最好的 JDBC 连接池,选择它就是最大的性能优化。
  2. 优化连接池参数
    • maximum-pool-size: 这是关键。设置过小会导致请求排队等待连接;设置过大会耗尽数据库资源或内存。需根据 数据库最大连接数限制应用并发量服务器资源 进行压测和调整。一个经验公式:poolSize = ((core_count * 2) + effective_spindle_count),但需实际测试。
    • connection-timeout: 设置过长会阻塞请求线程;过短会导致频繁失败。根据网络延迟和数据库负载设置。
    • max-lifetime: 避免连接老化。设置过短会增加创建连接的开销;过长可能导致连接失效。通常 30 分钟左右。
  3. 减少连接获取开销:HikariCP 本身已高度优化。确保 minimum-idle 设置合理,使常用连接常驻池中。
  4. 数据库端优化:确保数据库索引、查询语句高效。连接池优化解决的是连接获取问题,慢查询仍需数据库层面优化。
  5. 批量操作:对于大量数据插入/更新,使用 JdbcTemplatebatchUpdate 或 JPA 的批量操作,减少网络往返次数。
  6. 读写分离 (高级):对于读多写少的场景,可配置主从复制和读写分离数据源,将读请求分发到从库。

总结

通过 application.properties 配置 spring.datasource.* 属性,Spring Boot 能自动为你创建一个高效、可靠的数据库连接池(默认 HikariCP)。掌握基本配置、连接池调优、安全实践和错误排查是开发稳定应用的关键。

快速掌握路径

  1. 添加依赖spring-boot-starter-jdbc + 数据库驱动。
  2. 编写 application.properties:配置 url, username, password
  3. 启动应用:观察日志,确认 DataSource 初始化成功。
  4. 注入 DataSourceJdbcTemplate:编写简单代码测试连接。
  5. 优化:根据应用需求调整 HikariCP 参数(特别是 maximum-pool-size)。
  6. 安全:将生产密码移出 application.properties,使用环境变量或配置中心。

遵循这些步骤和最佳实践,你就能为 Spring Boot 应用成功配置并优化数据源。