第1篇-JDBC规范与DriverManager的legacy
约 1660 字大约 6 分钟
2026-05-24
四、Spring Boot 的"救赎":数据源自动装配
既然 DriverManager 有这么多问题,那现代 Java 应用是怎么获取数据库连接的呢?
答案是:使用数据源(DataSource),并且由 Spring Boot 自动装配。
4.1 DataSource 接口:JDBC 2.0 的新标准
// 类路径:javax.sql.DataSource
public interface DataSource extends CommonDataSource, Wrapper {
// 【核心】获取数据库连接
Connection getConnection() throws SQLException;
// 【核心】使用指定用户名和密码获取连接
Connection getConnection(String username, String password) throws SQLException;
}关键点:
DataSource是 JDBC 2.0(1999 年)引入的接口,它的定位是:作为一个连接工厂,可以返回任意类型的连接(池化的或非池化的)。- 与
DriverManager不同,DataSource的实现类可以是连接池(比如 Druid、HikariCP),也可以是简单的非池化数据源(比如 Spring 的DriverManagerDataSource)。
4.2 Spring Boot 自动装配入口:DataSourceAutoConfiguration
当你在 Spring Boot 项目中引入 spring-boot-starter-jdbc 或 mybatis-spring-boot-starter 时,Spring Boot 会自动帮你配置数据源。
核心配置类就是 DataSourceAutoConfiguration:
// 类路径:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@AutoConfiguration(before = SqlInitializationAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import(DataSourcePoolMetadataProvidersConfiguration.class)
public class DataSourceAutoConfiguration {
// 【核心】嵌入式数据库配置(如 H2、Derby)
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
// 【核心】连接池配置(如 HikariCP、Druid)
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({
DataSourceConfiguration.Hikari.class, // 默认使用 HikariCP
DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class,
DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class
})
protected static class PooledDataSourceConfiguration {
}
}白话文解释:
- Spring Boot 启动时会扫描所有自动配置类,
DataSourceAutoConfiguration就是其中之一。 - 它通过
@Conditional注解判断:当前环境适合使用嵌入式数据库,还是连接池? - 如果是生产环境(有
spring.datasource.url配置),就会选择连接池。默认使用 HikariCP(Spring Boot 2.x 的默认连接池)。 - 但是! 如果你引入了 Druid 的依赖,并且配置了
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource,那 Spring Boot 就会使用 Druid 连接池。
4.3 DataSourceProperties:配置属性的绑定
// 类路径:org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
// 【核心】JDBC URL
private String url;
// 【核心】用户名
private String username;
// 【核心】密码
private String password;
// 【核心】驱动类名(可以不写,Spring Boot 会自动推断)
private Class<? extends DataSource> type;
// 【核心】初始化 DataSourceBuilder(用于创建数据源)
public DataSourceBuilder<?> initializeDataSourceBuilder() {
return DataSourceBuilder.create(getClassLoader())
.type(getType())
.driverClassName(determineDriverClassName())
.url(determineUrl())
.username(determineUsername())
.password(determinePassword());
}
// 【核心】自动推断驱动类名
String determineDriverClassName() {
if (StringUtils.hasText(this.driverClassName)) {
return this.driverClassName;
}
// 【注意】根据 URL 自动推断驱动类
return DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
}
}白话文解释:
DataSourceProperties负责读取application.properties或application.yml中以spring.datasource开头的配置。- 你只需要写
spring.datasource.url=jdbc:mysql://localhost:3306/test,Spring Boot 就能自动推断出驱动类是com.mysql.cj.jdbc.Driver。 - 这就好比你告诉快递员"我要去朝阳区",快递员就能自动推断出"你应该坐地铁 10 号线"。
五、埋下伏笔:Druid 连接池的登场
说到这里,你可能会问:连接池到底是怎么工作的?为什么它比 DriverManager 快那么多?
这个问题,我们下一篇文章会详细解答。这里先预告一下 Druid 连接池的核心设计:
- 连接池的本质:在应用启动时,就预先创建一批数据库连接(比如 10 个),放在一个"池子"里。
- 借与还:当你需要连接时,从池子里"借"一个;用完后,"还"回池子。
- 连接复用:连接不会被真正关闭,而是被回收并标记为"空闲",等待下一个请求来借。
- 监控与过滤:Druid 还提供了强大的监控功能(比如 SQL 执行统计、慢查询监控)和过滤链机制(比如防火墙过滤)。
下一篇文章的预告:《数据源系列(二):Druid 连接池的整体架构》
六、总结与思考
今天我们一起回顾了 JDBC 规范的核心接口,深入理解了 DriverManager 的工作原理,并看到了它的局限性。同时,我们也了解了 Spring Boot 是如何通过自动装配来简化数据源配置的。
让我们用几个问题来检验一下今天的学习成果:
JDBC 规范的核心接口有哪些?它们的职责分别是什么?
Driver:驱动的"身份证",负责创建连接。Connection:数据库连接的抽象表示,提供事务控制方法。Statement/PreparedStatement:SQL 执行的载体。ResultSet:结果集的迭代器。
DriverManager 是如何找到合适的驱动的?
- 通过
registerDriver()注册驱动。 - 调用
getConnection()时,遍历已注册的驱动,让每个驱动判断是否能处理该 URL。 - JDBC 4.0+ 支持 SPI 自动加载驱动,无需手动
Class.forName()。
- 通过
为什么现代应用不再直接使用 DriverManager?
- 性能问题:每次都创建新连接,开销大。
- 连接泄漏:忘记关闭连接会导致资源耗尽。
- 缺乏监控:无法统计连接的使用情况。
Spring Boot 是如何自动配置数据源的?
- 通过
DataSourceAutoConfiguration自动配置类。 - 默认使用 HikariCP 作为连接池。
- 通过
DataSourceProperties绑定配置属性。
- 通过
七、扩展阅读
【扩展点】自定义数据源
如果你想自定义数据源(比如实现一些特殊的功能),可以这样做:
// 【扩展点】自定义数据源示例
@Configuration
public class CustomDataSourceConfig {
@Bean
@Primary
public DataSource customDataSource() {
// 【注意】这里可以返回任何实现了 DataSource 接口的类
return DataSourceBuilder.create()
.type(DruidDataSource.class) // 使用 Druid
.url("jdbc:mysql://localhost:3306/test")
.username("root")
.password("password")
.build();
}
}场景:当你需要使用多个数据源时(比如读写分离),就可以定义多个 DataSource Bean,并在使用时通过 @Qualifier 指定用哪个。
好了,今天的文章就到这里。下一篇,我们将深入 Druid 连接池的源码,看看它是如何管理连接的。敬请期待!
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发!你的支持是我继续创作的动力!
系列文章目录:
- 系列一:Spring 事务系列(已完成)
- 第1篇:@Transactional 注解的"前世今生"
- 第2篇:AOP 代理 —— 事务的"隐身衣"
- 第3篇:事务传播机制源码深度解析
- 第4篇:事务隔离级别的实现原理
- 第5篇:事务管理器的设计哲学
- 第6篇:事务资源的绑定与传递
- 第7篇:提交、回滚与异常规则
- 系列二:数据源系列(进行中)
- 第1篇:JDBC 规范与 DriverManager 的 legacy(本文)
- 第2篇:Druid 连接池的整体架构
- 第3篇:连接的借与还(getConnection 全流程)
- 第4篇:Druid 过滤链与监控统计
- 第5篇:MySQL 驱动的 JDBC 实现
- 第6篇:连接的生命周期与事务边界