Spring Boot 3 多数据源改造全流程:Druid、HikariCP 与 dynamic-datasource 实战总结
项目背景
初始架构与现状
在早期阶段,项目数据库结构简单,仅需连接一个主库,Druid的单数据源方案完全能够满足业务需求。
最初采用的是Spring Boot 3 + Druid 单数据源架构。
新需求的出现
随着业务的不断发展,项目逐渐暴露出以下痛点和新需求:
读写分离:部分业务场景对数据库读写压力较大,需要引入主从库,实现读写分离,提升系统性能和可用性。
多库动态切换:随着业务线扩展,部分功能需要访问不同的数据库,手动切换数据源变得繁琐且易出错。
Spring Boot 3 升级:项目升级到Spring Boot 3后,Druid部分版本兼容性不佳,且Spring官方推荐使用HikariCP作为默认连接池。
改造目标
基于上述背景,我们决定对原有的数据源架构进行升级,目标如下:
支持多数据源动态切换,满足主从库、分库等多场景需求。
简化数据源管理,减少手动切换和维护成本,提升开发效率。
兼容Spring Boot 3,采用官方推荐的HikariCP连接池,提升性能和稳定性。
技术选型
经过调研和对比,最终选定了 dynamic-datasource 作为多数据源动态切换的核心组件,配合Spring Boot 3默认的HikariCP连接池,实现多数据源的自动注册与灵活切换。
依赖选择、依赖分析与配置分析
依赖选择
原有依赖(Druid)
在改造前,项目依赖如下:
<!-- Druid 连接池(Spring Boot 3不再推荐) --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.24</version></dependency>
改造后依赖(HikariCP + dynamic-datasource)
步骤:
- 去掉 Druid 相关依赖,避免与 HikariCP 或 dynamic-datasource 冲突。
- 无需手动引入 HikariCP,Spring Boot 3 默认集成。
- 引入 dynamic-datasource,实现多数据源动态切换。
<!-- dynamic-datasource 多数据源 springboot3版本 -->
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot3-starter</artifactId><version>4.3.1</version>
</dependency>
<!-- HikariCP 由Spring Boot 3自动引入,无需单独声明 -->
依赖参考
迁移附加步骤
- 彻底移除 Druid 相关依赖,包括
druid-spring-boot-starter
和druid
本体,避免类冲突和自动装配干扰。 - 删除或注释掉 Druid 相关的配置项,如
spring.datasource.druid.*
、监控Servlet等。 - 检查代码中是否有 Druid 特有的API 或监控功能,如有需要用HikariCP或第三方监控方案替代。
- 确认配置文件中的
spring.datasource.type
为com.zaxxer.hikari.HikariDataSource
(可省略,Spring Boot 3默认即为HikariCP)。
连接池差异对比
对比项 | HikariCP | Druid |
---|---|---|
性能 | 极高,连接获取速度快,延迟低 | 性能较好,但在高并发下略逊于HikariCP |
内存占用 | 低,轻量级 | 相对较高 |
功能 | 专注于连接池本身,功能精简 | 功能丰富,支持SQL监控、Web界面等 |
配置复杂度 | 简单,参数少,易于上手 | 参数多,功能多,配置相对复杂 |
社区活跃度 | 国外主流,Spring官方推荐 | 国内主流,阿里维护,社区活跃 |
Spring Boot集成 | 2.x/3.x默认连接池,无需额外依赖 | 需单独引入依赖,Spring Boot 3兼容性需注意 |
监控能力 | 基本的JMX监控 | 内置强大的SQL、连接池监控 |
稳定性 | 非常高,广泛用于高并发场景 | 也很高,适合对监控有需求的场景 |
配置示例
多数据源配置示例(application-mysql.yaml):
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedynamic:primary: masterstrict: truedatasource:master:url: jdbc:mysql://xxx:3306/db1username: rootpassword: xxxslave:url: jdbc:mysql://xxx:3306/db2username: rootpassword: xxxhikari:maxPoolSize: 20minIdle: 10
-所有连接池参数统一写在hikari
下。
- dynamic-datasource会自动识别并注册所有配置的数据源,无需手动管理。
配置改造后遇到的问题
配置改造后遇到的问题
现象描述
- 配置好 dynamic-datasource 后,项目启动时报错/无法读取多数据源配置。
- 具体报错信息:
- 例如:
No qualifying bean of type 'javax.sql.DataSource' available
- 或者:
dynamic-datasource未生效,始终只用一个数据源
- 或者:
com.zaxxer.hikari.HikariConfig 1031 - HikariPool-1 - dataSource or dataSourceClassName or jdbcUrl is required.
- 例如:
排查思路
-
确认依赖版本:dynamic-datasource 4.3.1,Spring Boot 3.x,版本兼容无误。
-
检查配置文件:格式、缩进、profile激活均正确。
-
排查代码数据库连接:
- 发现项目早期代码中自定义了DataSource的@Bean,如下:
@Configuration
@Primary
public class DataBaseConfig {@Bean("master")@Primary@ConfigurationProperties("spring.datasource")public DataSource dataSource() {.......}
}@Configuration
public class JdbcTemplateConfig {@Beanpublic JdbcTemplate jdbcTemplate(@Qualifier("master") DataSource dataSource) {return new JdbcTemplate(dataSource);}
}
- 查阅dynamic-datasource官方文档,发现其自动装配机制依赖于Spring Boot的自动注册,如果手动注册了同类型的Bean,会导致自动装配失效。
结论与原理分析
Spring Boot自动装配与手动@Bean的关系
Spring Boot会先执行自动装配(如dynamic-datasource的多数据源注册),再加载你手动写的@Bean。
如果你手动注册了同类型的Bean(如DataSource),你的手动Bean会覆盖自动装配的Bean,最终Spring容器只会保留你手动的那个。
@Primary注解会让Spring在有多个同类型Bean时,优先注入被标记的那个。
问题本质
自定义的DataSource和JdbcTemplate Bean覆盖了dynamic-datasource的自动装配,导致多数据源配置失效。
dynamic-datasource的自动注册被“顶掉”,只剩下你手动注册的那个数据源,主从切换、动态路由等功能全部失效。
解决方案与建议
删除或注释掉所有自定义的DataSource和JdbcTemplate Bean配置类。
只保留dynamic-datasource的配置文件,交给dynamic-datasource自动装配。
需要用JdbcTemplate时,直接@Autowired注入即可,无需指定数据源,dynamic-datasource会自动注入主数据源。
如需切换数据源,使用dynamic-datasource提供的@DS注解即可。
总结
用dynamic-datasource时,不要手动写DataSource和JdbcTemplate的@Bean,一切交给自动装配。
遇到多数据源无效、配置不生效时,优先排查是否有自定义DataSource相关Bean。
Spring Boot3推荐使用HikariCP,Druid已不再是首选。