Spring Boot 3 原生不支持 Oracle UCP 自动装配,因 DataSourceAutoConfiguration 仅识别 HikariCP 等有限池类型;设 spring.datasource.type=oracle.ucp.jdbc.PoolDataSource 会被忽略,自动回退至 HikariCP,且所有 UCP 专属配置静默失效。

Spring Boot 3 原生不支持自动装配 Oracle UCP,必须手动配置 PoolDataSource 并显式启用 FCF 才能用于 RAC 高可用场景;直接写 spring.datasource.type=oracle.ucp.jdbc.PoolDataSource 会失败,因为 Spring Boot 的自动配置逻辑根本不识别 UCP。
为什么 spring.datasource.type 不生效
Spring Boot 3 的 DataSourceAutoConfiguration 只处理 HikariCP、Tomcat JDBC Pool、DBCP2 和极简的 SimpleDriverDataSource。UCP 不在白名单里,即使你写了 spring.datasource.type=oracle.ucp.jdbc.PoolDataSource,Boot 会跳过它,转而 fallback 到 classpath 下第一个可用的传统池(通常是 HikariCP),然后静默忽略所有 spring.datasource.oracleucp.* 配置项。
常见错误现象:application.yml 里一堆 spring.datasource.oracleucp.xxx 配置,但启动日志里始终显示 HikariPool-1,连接池监控也看不到 UCP 特有指标。
- 必须删掉
spring-boot-starter-jdbc或spring-boot-starter-data-jpa的默认依赖传递(它们会拉入 HikariCP) - 显式排除 HikariCP:
<exclusions><exclusion><groupId>com.zaxxer</groupId><artifactId>hikari-cp</artifactId></exclusion></exclusions> - UCP 初始化必须在
@PostConstruct或InitializingBean.afterPropertiesSet()中完成,不能靠属性绑定
PoolDataSource 手动配置的关键三步
UCP 不是“配完就跑”的组件,它需要 Java 代码级初始化才能激活高可用能力。核心是三件事:设连接参数、设池大小、显式开 FCF。
示例代码片段(放在 @Configuration 类中):
@Bean
public DataSource dataSource() {
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myrac-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=my_service)))");
pds.setUser("myuser");
pds.setPassword("mypass");
pds.setInitialPoolSize(2);
pds.setMinPoolSize(2);
pds.setMaxPoolSize(20);
pds.setFastConnectionFailoverEnabled(true); // ⚠️ 必须这行!
return pds;
}
-
setFastConnectionFailoverEnabled(true)不能省,也不能通过setConnectionProperties传oracle.jdbc.fanEnabled=true代替 - JDBC URL 必须用 SCAN 地址或 tnsnames 别名,禁用 Easy Connect 格式(如
@//host:port/service) - tnsnames.ora 中必须删干净
FAILOVER=ON、LOAD_BALANCE=ON、FAILOVER_MODE块,否则和 FCF 冲突
FCF 生效的前提条件容易被忽略
即使代码里调了 setFastConnectionFailoverEnabled(true),FCF 依然可能不工作——它依赖服务端和网络层的完整链路。
- 数据库侧:service 必须启用 FAN,执行
srvctl config service -d <db> -s <service>确认Failover type: SELECT - 网络侧:应用服务器必须能连通 RAC 所有节点的 ONS 端口(默认 6200),用
onsctl ping -h rac1-vip -p 6200验证 - 驱动侧:ojdbc8+ 必须在 classpath,且不能混用不同版本(比如 ojdbc8 + ojdbc11 同时存在)
- 现象验证:故意 kill 一个 RAC 实例,观察应用日志是否在 2–3 秒内打印出
FAN event received: DOWN,而不是等 30 秒超时后报ORA-03113
连接亲和性不是靠 URL 或池参数控制的
很多团队误以为加个 affinity=primary 到 JDBC URL 就能实现连接亲和,其实 UCP 的亲和性完全基于运行时标签(connectionLabel),和连接字符串无关。
要让同一批请求路由到同一个物理连接(例如保持临时表上下文),必须在获取连接后手动打标:
Connection conn = dataSource.getConnection();
conn.setClientInfo("CONNECTION_LABEL", "session_123"); // 或用 setConnectionLabel()
// 后续同一线程内复用该 conn 即可维持亲和
- 标签值由业务自己生成和管理,UCP 不解析其含义,只做哈希匹配
- 不能依赖 Spring 的
@Transactional或连接自动绑定机制,必须显式持有并复用同一Connection实例 - 如果用了 MyBatis 或 JPA,需绕过框架默认连接管理,改用
DataSourceUtils.doGetConnection()+ 手动归还
真正麻烦的从来不是写几行配置,而是确认 FAN 事件是否真从数据库发出来、ONS 是否真的通、以及你的业务线程是否真的在复用带 label 的连接——这三个点任何一个断掉,UCP 就退化成普通连接池。


















