Camel应用数据库故障转移异常处理失效问题求助
你遇到的路由停滞、事务回滚失败问题,主要有这几个核心原因:
自定义重试逻辑未适配Camel的Exchange生命周期
你写的RecoverableExceptionHandlingStrategy只是做了Thread.sleep和计数,但没有告诉Camel要重新投递当前Exchange。Camel的异常处理流程中,如果没有明确标记要重试或处理,Exchange就会卡在异常处理环节,导致路由停滞。另外,用静态变量count计数是全局的,多Exchange并发处理时会彻底混乱,根本无法准确控制单个Exchange的重试次数。失效连接未被清理,事务回滚依赖无效资源
当数据库连接失效后,你的JPATransactionManager和studentJPARepository可能还持有这个失效的连接。事务回滚时尝试用这个无效连接操作数据库,就会抛出回滚失败的错误,进一步阻塞Exchange的处理流程。未利用Camel原生重试机制的事务管理能力
Camel的onException内置了重试、事务回滚、Exchange重置的逻辑,你自己手写的处理器完全绕过了这些机制,导致事务上下文无法正确重置,重试时还是用旧的失效连接和事务上下文。
我建议你放弃自定义重试处理器,改用Camel原生的重试机制,同时配合连接池配置解决连接复用问题,具体步骤如下:
1. 用Camel原生onException配置重试逻辑
Camel的onException可以直接配置重试次数、间隔,还能自动处理事务回滚和Exchange的重新投递。修改你的registerExceptionHandler方法:
import org.apache.camel.Exchange; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyRouteBuilder extends SpringRouteBuilder { private static final Logger log = LoggerFactory.getLogger(MyRouteBuilder.class); @Override public void configure() throws Exception { registerExceptionHandler(); addRoute(); } private void addRoute() { from("file:/DHBSI/data/input?fileName=whdh90151.csv") .id("MyRoute") .policy(transactionRequiredPolicy) .process(exchange -> { // 你的业务逻辑 StudentJPAEntity student = new StudentJPAEntity(); // ... 填充数据 studentJPARepository.save(student); }).end(); } private void registerExceptionHandler() { // 处理数据库连接类异常,配置重试 onException(JDBCConnectionException.class, SocketException.class) .maximumRedeliveries(5) // 最多重试5次 .redeliveryDelay(1000) // 每次间隔1000ms .rollbackOnly() // 确保事务强制回滚,清理失效的事务上下文 .onRedelivery(exchange -> { // 重试时的日志记录,用Camel自带的重试计数器 int retryCount = exchange.getIn().getHeader(Exchange.REDELIVERY_COUNTER, 0); Exception ex = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); log.warn("数据库连接异常,正在进行第 {} 次重试,原因: {}", retryCount + 1, ex.getMessage()); }) .handled(false); // 标记为未处理,让Camel重新投递Exchange // 处理其他不可恢复异常,关闭应用 onException(Exception.class) .process(exchange -> { Exception ex = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); log.error("发生不可恢复异常,即将关闭应用", ex); System.exit(-1); }); } }
2. 配置JPA连接池,自动清理失效连接
要解决连接复用问题,需要让你的数据库连接池自动检测并剔除失效连接。如果用的是Spring Boot默认的HikariCP,在application.properties或application.yml中添加以下配置:
# HikariCP连接池配置 spring.datasource.hikari.connection-test-query=SELECT 1 spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.validate-on-borrow=true
connection-test-query:每次从连接池获取连接前,执行一个简单的SQL校验连接是否可用max-lifetime:连接的最大生命周期,到期自动销毁,避免长期持有失效连接validate-on-borrow:获取连接时立即校验,确保拿到的是可用连接
这样,当数据库恢复后,重试时连接池会自动返回新的可用连接,你的studentJPARepository就能正常执行保存操作了。
3. 验证事务上下文重置
确保你的transactionRequiredPolicy使用的JPATransactionManager是Spring管理的Bean,每次重试时Camel会自动开启新的事务,使用连接池提供的新连接,不会复用之前失效的事务上下文。
- Camel原生重试机制会在每次重试前重置Exchange的状态,确保业务逻辑重新执行时用的是干净的上下文
rollbackOnly()会强制回滚当前失效的事务,避免事务上下文阻塞- 连接池的校验配置确保重试时拿到的是可用的新连接,不会再用之前失效的连接
- 用
Exchange.REDELIVERY_COUNTER代替静态变量,每个Exchange的重试计数独立,不会出现并发问题
内容的提问来源于stack exchange,提问作者Kuntal Chakraborty

