大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
数据库访问
Spring Data JPA 把 SQL 藏得很深,但排障时你仍需要 JDBC 与连接池 的直觉。本课衔接 java-core-essentials 的 I/O 与异常处理,为 orm-essentials 与 spring-boot-essentials 的 DataSource 配置打地基。
学习目标
- 用 JDBC 完成「连接 → 预编译 → 查询 → 关闭」完整链路
- 理解连接池为何存在,以及 HikariCP 的核心参数
- 区分 JDBC 模板、MyBatis 与 JPA 的适用场景
JDBC 最小可用示例
public record User(long id, String email) {}
public class UserRepository {
private final DataSource dataSource;
public UserRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
public Optional<User> findById(long id) throws SQLException {
String sql = "SELECT id, email FROM users WHERE id = ?";
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setLong(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
return Optional.empty();
}
return Optional.of(new User(rs.getLong("id"), rs.getString("email")));
}
}
}
}
要点:始终用 PreparedStatement 防 SQL 注入;用 try-with-resources 确保连接归还池子。
连接池:HikariCP 配置直觉
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/demo");
config.setUsername("app");
config.setPassword("secret");
config.setMaximumPoolSize(10); // 并发上限,不是越大越好
config.setConnectionTimeout(5_000); // 借连接等待毫秒
config.setPoolName("demo-pool");
DataSource ds = new HikariDataSource(config);
| 参数 | 含义 | 常见误区 |
|---|---|---|
| maximumPoolSize | 同时借出的连接数 | 设成 100 反而拖垮 DB |
| connectionTimeout | 池满时等待时间 | 与 SQL 执行超时不是一回事 |
| idleTimeout | 空闲连接回收 | 过短导致频繁建连 |
Spring Boot 默认 HikariCP;你在 application.yml 里改的 spring.datasource.hikari.* 就是这里。
选型速查
- 纯 JDBC + 手写 SQL:报表、批量 ETL、极致 SQL 控制
- JdbcTemplate / jOOQ:中等复杂度,仍想写 SQL
- JPA / Hibernate:领域模型驱动,CRUD 为主(见 jev-hibernate)
- MyBatis:SQL 与 Java 显式映射,国内项目常见
练习
- 用 H2 内存库实现
UserRepository.findById,写 JUnit 集成测试 - 故意把
maximumPoolSize设为 1,并发 5 个查询观察connectionTimeout行为 - 对照 Spring Boot 项目的
application.yml,说出三项 Hikari 配置的含义
小结
JDBC 是底线技能;连接池是性能与稳定性的第一道关。 下一课进入 Hibernate 的 Session 与映射世界。