2. Spring JDBC与数据源基础
在Spring企业数据访问体系中,JDBC并没有被“淘汰”,而是被重新组织:Spring把连接获取、异常转换、资源释放这些重复且容易出错的环节封装起来,让开发者把注意力放在SQL与结果映射上。理解这条链路的起点,是DataSource接口。
一、DataSource:连接的抽象工厂
javax.sql.DataSource是JDBC规范定义的接口,它替代了早期直接使用DriverManager.getConnection()的方式。核心方法只有两个:getConnection()与getConnection(String user, String password)。它的价值在于:调用方只依赖接口,不关心底层是单连接、连接池还是分布式数据源。
从实现形态看,DataSource可分为三类:
- 基础实现:如
DriverManagerDataSource,每次调用都新建物理连接,仅适合测试或极低频场景。 - 连接池实现:如HikariCP、Druid、DBCP2、Tomcat JDBC Pool,复用物理连接,是生产环境的标准选择。
- 路由/代理实现:如
AbstractRoutingDataSource,用于多数据源动态切换。
连接池的本质是“用空间换时间”:预先建立若干物理连接放入池中,应用借出、归还,避免每次TCP握手与数据库认证的开销。选型时通常关注以下参数:
| 参数 | 含义 | 典型取值 |
|---|---|---|
| maximumPoolSize | 池中最大连接数 | CPU核数×2~4,或按DB上限反推 |
| minimumIdle | 最小空闲连接数 | 与maximumPoolSize接近,减少抖动 |
| connectionTimeout | 获取连接的最长等待 | 3000ms |
| idleTimeout | 空闲连接回收时间 | 600000ms |
| maxLifetime | 连接最大存活时间 | 小于DB的wait_timeout |
HikariCP以轻量、低延迟著称,是Spring Boot 2.x以来的默认连接池;Druid则内置监控统计、SQL防火墙与WallFilter,适合需要可视化监控与审计的场景。二者并非互斥,选型取决于是否需要Druid的监控生态。
二、JdbcTemplate核心API
JdbcTemplate是Spring JDBC的核心类,它持有DataSource,负责模板化流程:获取连接→创建Statement→执行→处理结果→释放资源→转换异常。常用API如下:
// 查询单值
Integer count = jdbcTemplate.queryForObject(
"select count(*) from t_user where status = ?", Integer.class, 1);
// 查询对象列表
List<User> users = jdbcTemplate.query(
"select id, name, email from t_user where age > ?",
(rs, rowNum) -> new User(rs.getLong("id"),
rs.getString("name"),
rs.getString("email")),
18);
// 更新
int affected = jdbcTemplate.update(
"update t_user set email = ? where id = ?", "a@x.com", 1001L);
其中RowMapper负责把ResultSet的一行映射为对象,queryForObject在结果多于一行时会抛出IncorrectResultSizeDataAccessException,这是常见的排错点。批量操作使用batchUpdate,配合BatchPreparedStatementSetter可显著降低网络往返。
三、Spring Boot自动配置与多数据源初步认知
Spring Boot通过DataSourceAutoConfiguration自动装配DataSource。当类路径存在HikariCP时,默认创建HikariDataSource;若配置了spring.datasource.url等属性,则直接绑定。典型配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useSSL=false
username: app
password: secret
hikari:
maximum-pool-size: 20
connection-timeout: 3000
当需要访问多个库时,自动配置不再适用,需要手动定义多个DataSource Bean,并用@Primary标记主数据源,再分别创建对应的JdbcTemplate。此时应关闭自动配置的单一数据源推断,避免Bean冲突。
上图展示了从业务代码到数据库的完整链路:业务代码依赖JdbcTemplate,JdbcTemplate依赖DataSource接口,接口背后由HikariCP或Druid提供连接池能力,最终落到物理数据库。右侧虚线框提示了多数据源场景下的扩展方向。
掌握本节内容后,应能回答三个问题:DataSource为什么是接口而非具体类;HikariCP与Druid各自适合什么场景;JdbcTemplate的query、update、batchUpdate分别对应什么操作。这些是后续事务管理、MyBatis整合与多数据源路由的基础。