java多数据源通过为每个数据库配置独立连接池实现按需路由,关键在于分离配置、统一调度、规避事务冲突;各池始终就绪,路由发生在getconnection()时,事务内切换无效。

Java 中多数据源连接池不是“同时启用所有池”,而是让每个数据源拥有独立的连接池实例,并在运行时按需路由到对应池。关键在于分离配置、统一调度、规避事务冲突。
每个数据源配一个独立连接池
不能把多个数据库 URL 塞进同一个 HikariCP 或 Druid 配置里——这会报错或连错库。必须为每个真实库(如 master、slave、达梦、Oracle)单独声明一个 DataSource Bean:
- 主库用
@Primary标记,或在 dynamic-datasource 中设为 default - 从库、异构库分别配独立的
HikariDataSource,URL、驱动类、用户名密码、连接池参数(maxPoolSize、idleTimeout等)均可差异化设置 - 达梦要写对驱动:
dm.jdbc.driver.DmDriver;Oracle 注意oracle.jdbc.OracleDriver和 URL 格式
靠路由机制切换,不靠启停池
切换发生在 getConnection() 被调用的瞬间,由 AbstractRoutingDataSource 查看当前线程绑定的 key(通常存于 ThreadLocal),然后从已初始化好的多个池中选一个返回连接:
- 使用
@DataSource("slave")注解时,AOP 自动执行DynamicDataSourceContextHolder.set("slave"),方法退出后自动clear() - 若用
dynamic-datasource-spring-boot-starter,它已封装好整套逻辑,你只需配 yml + 加注解 - 底层所有连接池始终就绪,只是“被选中”的时机由线程上下文决定
事务内切换无效,必须前置
Spring 的 DataSourceTransactionManager 在事务开始时就绑定首个获取的 Connection,并在整个事务生命周期内复用它:
- @Transactional 方法内部再调用
@DataSource("xxx")不生效——连接早已确定 - 读写分离场景下,可结合
@Transactional(readOnly = true)+ AOP 自动路由到 slave,但前提是该方法未被外层事务包裹 - 真要跨库写操作?只能拆成多个无事务子方法,或引入 Seata 等分布式事务框架
验证是否真正生效
光有配置不等于池在跑,建议两处检查:
- 启动日志搜索
HikariPool-1、HikariPool-2—— 应看到多个 pool 名称,说明多个连接池实例已初始化 - 加个简单测试接口,分别用
@DataSource("master")和@DataSource("slave")查询,观察日志中实际使用的 URL 和连接池名是否匹配
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











