一、核心概念
在 Spring Boot 中,数据源 (DataSource) 是应用程序连接和操作数据库的桥梁。它封装了数据库连接池、连接参数、认证信息等。Spring Boot 的 自动配置 (Auto-configuration) 机制会根据类路径上的依赖(如 spring-boot-starter-jdbc
或 spring-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. 自动配置原理
- 检测到
spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
等依赖。 - 检查
application.properties
中是否配置了spring.datasource.*
属性。 - 如果配置了必要属性(如
url
,username
,password
),则自动创建DataSource
Bean。 - 如果类路径有 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 中的 username 和 password 是否正确。确认数据库用户有连接权限。 |
Unknown database 'mydb' |
数据库不存在 | 在数据库管理工具中创建指定的数据库 (CREATE DATABASE mydb; )。 |
Communications link failure / Connection refused |
数据库服务未启动或端口错误 | 确认数据库服务(如 MySQL, PostgreSQL)正在运行。检查 application.properties 中的 host 和 port 是否正确。 |
The server time zone value '...' is unrecognized |
时区配置问题 (常见于 MySQL) | 在 JDBC URL 中添加 serverTimezone=UTC 或 serverTimezone=Asia/Shanghai 等有效时区。 |
HikariPool-1 - Exception during pool initialization |
连接池初始化失败 | 检查上述所有连接问题。确认网络可达。检查连接池参数(如 maximum-pool-size )是否合理。 |
No qualifying bean of type 'javax.sql.DataSource' available |
数据源未配置或自动配置未触发 | 确保添加了 spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa 依赖。检查 application.properties 文件位置和拼写。确认配置了 spring.datasource.url 等必需属性。 |
四、注意事项
- 密码安全:
application.properties
中的密码是明文的。生产环境切勿直接存放明文密码。应使用:- 环境变量 (
SPRING_DATASOURCE_PASSWORD
) - 配置中心 (如 Spring Cloud Config, Consul, Zookeeper)
- 云平台密钥管理服务 (如 AWS Secrets Manager, Azure Key Vault)
- 命令行参数 (
--spring.datasource.password=mypassword
)
- 环境变量 (
- JDBC URL 参数:不同的数据库和驱动可能需要特定的连接参数(如
useSSL
,serverTimezone
,allowPublicKeyRetrieval
for MySQL 8)。查阅对应数据库驱动的文档。 - 驱动类名:Spring Boot 能根据
spring.datasource.url
的协议(jdbc:mysql
,jdbc:postgresql
)自动推断驱动类。通常可以省略spring.datasource.driver-class-name
。如果自动推断失败再手动指定。 - 连接池选择:优先使用 HikariCP(Spring Boot 默认),性能最好。除非有特殊需求,否则无需更换。
- 属性前缀:HikariCP 的配置必须以
spring.datasource.hikari.
开头。其他连接池(如 Tomcat)使用spring.datasource.tomcat.*
。 - 多数据源:
application.properties
默认只配置一个主数据源。配置多个数据源需要更复杂的@Configuration
类和@Primary
注解。
五、使用技巧
- 使用环境变量覆盖:在部署时,通过环境变量覆盖
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
- 配置文件分 profile:使用
application-dev.properties
,application-prod.properties
等,通过spring.profiles.active=dev
激活不同环境的配置。 - HikariCP 监控:HikariCP 提供了 JMX MBean,可以监控连接池状态(活跃连接、空闲连接、等待线程等)。可通过 JConsole 或集成 Prometheus + Grafana 监控。
JdbcTemplate
/NamedParameterJdbcTemplate
:直接使用DataSource
较底层,推荐使用JdbcTemplate
简化 JDBC 操作。DataSourceBuilder
:在需要编程式创建DataSource
时(如多数据源),可使用DataSourceBuilder
。- 健康检查:Spring Boot Actuator 的
/actuator/health
端点会检查数据源连接状态。
六、最佳实践
- 使用连接池:必须使用连接池(如 HikariCP),绝不能使用
DriverManagerDataSource
(无池化,性能极差)。 - 合理设置连接池大小:
maximum-pool-size
: 根据数据库最大连接数、应用并发量、服务器资源估算。通常从 10-20 开始,根据监控调整。避免过大,耗尽数据库连接或内存。minimum-idle
: 保持一定数量的空闲连接,减少获取新连接的延迟。通常设为与maximum-pool-size
相同或略小。
- 设置超时时间:
connection-timeout
: 避免请求无限等待连接。设置合理值(如 20s)。max-lifetime
: 防止连接过长导致问题(如数据库重启后连接失效)。通常设为几分钟到几十分钟。idle-timeout
: 回收长时间不用的连接。
- 生产环境使用安全配置:绝对不要在代码仓库中存放生产数据库的明文密码。使用环境变量、配置中心或密钥管理服务。
- 配置正确的时区:在 JDBC URL 中明确指定
serverTimezone
,避免日期时间数据错乱。 - 启用 SSL (生产环境):在生产环境中,如果网络不可信,应配置数据库连接的 SSL/TLS 加密。
- 监控连接池:集成监控工具,持续观察连接池的活跃度、等待队列等指标,及时发现性能瓶颈。
- 使用 JPA/Hibernate 或 MyBatis:对于复杂的 ORM 操作,优先考虑使用 JPA/Hibernate 或 MyBatis 等框架,而不是直接使用
JdbcTemplate
。
七、性能优化
- 选择 HikariCP:它是目前性能最好的 JDBC 连接池,选择它就是最大的性能优化。
- 优化连接池参数:
maximum-pool-size
: 这是关键。设置过小会导致请求排队等待连接;设置过大会耗尽数据库资源或内存。需根据 数据库最大连接数限制、应用并发量 和 服务器资源 进行压测和调整。一个经验公式:poolSize = ((core_count * 2) + effective_spindle_count)
,但需实际测试。connection-timeout
: 设置过长会阻塞请求线程;过短会导致频繁失败。根据网络延迟和数据库负载设置。max-lifetime
: 避免连接老化。设置过短会增加创建连接的开销;过长可能导致连接失效。通常 30 分钟左右。
- 减少连接获取开销:HikariCP 本身已高度优化。确保
minimum-idle
设置合理,使常用连接常驻池中。 - 数据库端优化:确保数据库索引、查询语句高效。连接池优化解决的是连接获取问题,慢查询仍需数据库层面优化。
- 批量操作:对于大量数据插入/更新,使用
JdbcTemplate
的batchUpdate
或 JPA 的批量操作,减少网络往返次数。 - 读写分离 (高级):对于读多写少的场景,可配置主从复制和读写分离数据源,将读请求分发到从库。
总结
通过 application.properties
配置 spring.datasource.*
属性,Spring Boot 能自动为你创建一个高效、可靠的数据库连接池(默认 HikariCP)。掌握基本配置、连接池调优、安全实践和错误排查是开发稳定应用的关键。
快速掌握路径:
- 添加依赖:
spring-boot-starter-jdbc
+ 数据库驱动。 - 编写
application.properties
:配置url
,username
,password
。 - 启动应用:观察日志,确认
DataSource
初始化成功。 - 注入
DataSource
或JdbcTemplate
:编写简单代码测试连接。 - 优化:根据应用需求调整 HikariCP 参数(特别是
maximum-pool-size
)。 - 安全:将生产密码移出
application.properties
,使用环境变量或配置中心。
遵循这些步骤和最佳实践,你就能为 Spring Boot 应用成功配置并优化数据源。