Spring Batch使用多数据源出现JPA EntityManager事务打开失败异常
异常原因
该异常是因为同一线程中已经绑定了某数据源的ConnectionHolder资源,尝试绑定第二个数据源的事务资源时出现冲突,核心原因是Spring Batch的Step级事务和你在Reader、Writer上自定义的@Transactional注解冲突,同时配置存在低级错误。
现有配置问题
- Sybase数据源配置错误
你在SybasedbConfig的sybaseDataSource方法中,错误读取了PostgreSQL的驱动配置:
// 错误写法,读的是PostgreSQL的驱动key dataSource.setDriverClassName(env.getProperty("datasource.posgres.driver-class-name"));
需要修正为你配置文件中Sybase数据库对应的驱动配置key。
- 事务嵌套冲突
你在Step配置中已经指定了transactionManager(positionTransactionManager),意味着整个Chunk的执行生命周期都受PostgreSQL事务管理器管控,同时你又在Reader上加了Sybase的事务注解、Writer上加了PostgreSQL的事务注解,两个事务在同一线程的Chunk周期内嵌套,导致资源未解绑就重复绑定。
解决方案
方案一:拆分多Step隔离事务
将读Sybase和写PostgreSQL拆分为两个独立Step,每个Step指定对应自身数据源的事务管理器:- 第一个Step负责读取Sybase数据,配置transactionManager为
SybaseTransactionManager,将读取到的结果存储到Job执行上下文或临时存储介质 - 第二个Step负责读取临时存储的结果,写入PostgreSQL,配置transactionManager为
positionTransactionManager
两个Step的事务完全隔离,不会出现线程资源绑定冲突。
- 第一个Step负责读取Sybase数据,配置transactionManager为
方案二:使用分布式事务管理器
如果必须在同一个Step中操作两个数据源,需配置JtaTransactionManager作为全局分布式事务管理器,统一管控两个数据源的事务生命周期,避免独立事务管理器的资源绑定冲突。临时修复方案
如果暂时不想调整结构,先删除Reader和Writer上自定义的所有@Transactional注解,同时修正Sybase的驱动配置错误,大部分场景下可以直接解决问题。
内容的提问来源于stack exchange,提问作者Yuvraj Adak
相关产品推荐
相关产品推荐

