oracle多数据源下@transactional不生效,是因为默认datasourcetransactionmanager不感知oracle xid,需用jtatransactionmanager+ucp的poolxadatasourceimpl,并启用数据库分布式事务支持。

Oracle 事务与 Spring 事务“一致”,不是指行为上完全等价,而是指:当 Spring 声明了 @Transactional,Oracle 真的按预期参与了全局事务控制(尤其是多数据源、跨库场景)。默认情况下,它们根本不一致——DataSourceTransactionManager 对 Oracle XID 完全无感,所谓“事务”只是 JDBC 层的本地 commit/rollback,连 Oracle 的 v$transaction 都查不到对应分支。
必须用 JTA + XA 才能对齐 XID,否则永远是两套独立事务。
为什么 @Transactional 在 Oracle 多数据源下不生效
现象:@Transactional 方法里操作两个 Oracle 数据源(ds-order 和 ds-audit),日志显示分别 committing transaction on datasource 'ds-order' 和 committing transaction on datasource 'ds-audit',但任意一个失败,另一个仍提交成功。
原因:Spring 默认的 DataSourceTransactionManager 只管单个 Connection 的 commit()/rollback(),它不知道、也不传递 Oracle 的全局事务 ID(XID)。两个数据源各自生成独立 XID(XIDUSN/XIDSLOT/XIDSQN 完全不同),Oracle 服务端根本没把它们当作同一分布式事务处理。
- 这不是 Spring “没回滚”,而是压根没进两阶段提交(2PC)流程
-
v$transaction查不到跨数据源的统一事务上下文 - 即使用了
OracleXADataSource,若 Spring 事务管理器不是JtaTransactionManager,照样无效
必须用 JtaTransactionManager + UCP PoolXADataSourceImpl
Oracle 官方明确弃用 oracle.jdbc.xa.client.OracleXADataSource(已标记为 deprecated),尤其在 12c+ 版本。正确做法是用 Oracle Universal Connection Pool(UCP)提供的 oracle.ucp.jdbc.PoolXADataSourceImpl。
Spring Boot 2.3+ 还需显式排除自动配置,否则 DataSourceTransactionManagerAutoConfiguration 会抢注默认事务管理器:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
关键配置项:
xaDataSourceClassName=oracle.ucp.jdbc.PoolXADataSourceImpl-
connectionFactoryClassName=oracle.jdbc.xa.client.OracleXADataSource(仅作底层驱动,不直接实例化) -
JtaTransactionManagerBean 必须加@Primary注解 - 所有
@Transactional必须显式指定管理器:@Transactional(transactionManager = "jtaTransactionManager")
Oracle 数据库侧必须启用分布式事务支持
即使 Java 侧配对了 XA 和 JTA,Oracle 实例若未开启分布式事务功能,分支注册仍会失败,典型报错:ORA-02049: timeout: distributed transaction waiting for lock 或 XAER_RMERR。
确认命令:
SELECT * FROM v$option WHERE parameter = 'Distributed Transaction Processing';
返回 TRUE 才表示启用。如为 FALSE,需 DBA 执行:
ALTER SYSTEM SET distributed_transactions = 10 SCOPE=BOTH;
另外,长事务容易超时,默认 distributed_lock_timeout=60 秒,建议调高:
ALTER SYSTEM SET distributed_lock_timeout=120 SCOPE=BOTH;
还有个隐蔽坑:xaDataSourceName 在同一 JVM 内不能重复。多个 PoolXADataSourceImpl 实例若设了相同名称,Oracle 服务端会混淆分支,导致注册失败。
XA 模式下最容易被忽略的三个点
一是 Oracle 的 XID 不是靠 Spring 自动对齐的,它依赖底层 XADataSource 实现和 JtaTransactionManager 协同生成;二是 UCP 的连接池行为与传统 HikariCP 不同,不能简单套用配置;三是 distributed_transactions 参数是实例级开关,重启后失效,必须写入 spfile 或 pfile 持久化。











