最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何配置Spring Boot来支持Oracle的高可用数据源切换
时间:2026-07-15 19:54:52 编辑:袖梨 来源:一聚教程网
Oracle高可用数据源切换必须用AbstractRoutingDataSource自定义路由,因Spring Boot原生不支持RAC/Data Guard自动故障转移;需结合健康检查、线程绑定、驱动版本匹配及事务隔离等机制实现可靠切换。
Oracle高可用数据源切换必须用 AbstractRoutingDataSource 自定义路由
spring boot 原生不提供 oracle 高可用(如 rac、data guard 切换)的自动故障转移能力,spring.datasource.url 写死单个地址时,一旦实例宕机就直接抛 sqlexception: io error: connection reset。必须自己实现路由逻辑,让连接在多个 oracle 实例间动态选择。
关键点在于:不能只靠 JDBC URL 的 failover 参数(如 failover=true&loadBalance=true),Oracle 官方驱动对 RAC 的透明应用故障转移(TAF)仅支持 OCI 连接,Thin Driver 无法触发 TAF 回调;而 Data Guard 的角色切换(primary ⇄ standby)更需应用层感知状态并主动重连。
- 继承
AbstractRoutingDataSource,重写determineCurrentLookupKey() - 用
ThreadLocal绑定当前会话期望的数据源 ID(如"rac-node1"或"dg-standby"),而非全局轮询 - 配合健康检查线程定期 ping 各实例(执行
SELECT 1 FROM DUAL),把不可用节点从候选列表中临时剔除 - 切面拦截
@Transactional方法,在事务开始前校验目标数据源是否存活,不存活则抛自定义异常或 fallback 到备用源
ojdbc8 驱动版本与连接参数必须匹配 Oracle 版本
用错驱动或参数会导致连接成功但后续执行失败,典型现象是:能连上、能查 DUAL,但一跑含序列/LOB/高级队列的 SQL 就报 ORA-00904: invalid identifier 或 ORA-22922: nonexistent LOB value。
例如 Oracle 19c RAC 环境下,若用 ojdbc6,即使配置了 oracle.net.TNS_ADMIN 指向 tnsnames.ora,也无法解析 SCAN 地址中的负载均衡信息;而 ojdbc8(对应 JDK 8+)才完整支持 12c+ 的新特性,包括 Application Continuity 和 Transparent Application Failover 的基础协议字段。
- Oracle 12.1–19c → 用
com.oracle.database.jdbc:ojdbc8:21.10.0.0(Maven 中央库最新稳定版) - JDBC URL 必须显式启用 RAC 支持:
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=node1)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=node2)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=orcl)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=3)(DELAY=5))) - 禁用
oracle.jdbc.useFetchSizeWithLongColumn(默认 true),否则大字段查询可能内存溢出
事务方法内切换数据源会破坏 ACID,必须禁止
在同一个 @Transactional 方法里,先查主库再写备库,或中间调用 DataSourceContextHolder.set("dg-standby"),会导致 Spring 的 DataSourceTransactionManager 拿到错误的物理连接 —— 事务已绑定初始数据源,后续切换只会让非事务操作“看似”走新库,但实际被回滚或隔离失效。
真实场景中常见错误:用户服务调用订单服务,订单服务内部用了 @DS("dg-standby") 注解,结果事务提交后,主库没更新、备库却写了脏数据,最终 DG 同步失败且无法回退。
- 所有数据源切换注解(如
@DataSource或自定义@DS)必须加在 **非事务方法** 上,或确保该方法本身不参与外层事务(@Transactional(propagation = Propagation.NOT_SUPPORTED)) - 读写分离场景下,写操作只能走主库,且必须由独立事务方法承载;读操作可走备库,但需明确声明
@Transactional(readOnly = true)并配专用数据源 - 如果业务强依赖跨库一致性(如双写校验),改用消息队列 + 最终一致性,不要在事务内硬切
Druid 连接池的 validationQuery 对 Oracle 要设为 SELECT 1 FROM DUAL
很多团队沿用 MySQL 的 SELECT 1,但在 Oracle 下 Druid 会静默忽略校验,导致连接池长期持有已断开的连接,直到下次真正使用时才暴露 SQLException: Closed Connection,拖慢整个请求链路。
Druid 默认的 testWhileIdle + timeBetweenEvictionRunsMillis 机制依赖 validationQuery 执行结果判断连接有效性,Oracle 没有 SELECT 1 语法,必须显式指定 DUAL 表。
- application.yml 中务必配置:
spring.datasource.druid.validation-query: SELECT 1 FROM DUAL - 同时设置
spring.datasource.druid.test-on-borrow: false(避免每次取连接都查一次,影响性能),靠空闲检测兜底即可 - 若用
dynamic-datasource-spring-boot-starter,它底层也基于 Druid,同样要覆盖该配置,否则多数据源场景下某个库的连接池会持续泄漏
最易被忽略的是:RAC 节点间状态不同步时,健康检查可能误判。比如一个节点刚重启、SMON 还没完成实例恢复,此时 SELECT 1 FROM DUAL 能通,但 INSERT INTO ... 仍会报 ORA-03113: end-of-file on communication channel。建议在生产环境把健康检查升级为执行轻量级业务语句(如查一个带索引的小表主键),而非仅依赖 DUAL。
相关文章
- 王者荣耀世界零氪玩家如何生存 07-28
- 快手极速版怎么绑定手机号 07-28
- 明日方舟和轻松小熊联动活动内容一览 07-28
- 逆战未来黎明之光 逆战未来黎明之光玩法机制与新手入门指南 07-28
- 植物大战僵尸融合版毁灭土豆地雷介绍 07-28
- 逆战未来飓风之龙 逆战未来飓风之龙武器获取方法详解 07-28