Spring 批管理事务回滚时重试不起作用
Retry not working when Spring Batch managed transaction rolls back
在我的 Spring 批处理作业的其中一个步骤中,我正在尝试对其进行配置,以便在 ObjectOptimisticLockingFailureException
发生时可以重试该步骤,希望重试能够成功。
@Bean
public Step myStep(StaxEventItemReader<Response> staxEventResponseReader,
ItemWriter<Response> itemWriter,
ItemProcessor<? super Response, ? extends Response> responseProcessor) {
return stepBuilderFactory.get("myStep")
.<Response, Response>chunk(1)
.reader(staxEventResponseReader)
.processor(responseProcessor)
.writer(itemWriter)
//.faultTolerant().retryLimit(3).retry(Exception.class)
.build();
}
该步骤的 writer 逻辑非常简单:它尝试从数据库中读取一行,一旦找到该行,就会对其进行更新。我能够通过在 find 方法之后立即设置断点来重现 ObjectOptimisticLockingFailureException
,手动碰撞数据库中行的 version
列并提交它,然后恢复。
但是,在我的步骤中取消注释重试定义后,没有尝试重试。经过一些调试,似乎 Spring 重试逻辑在块的事务中;但是由于 ObjectOptimisticLockingFailureException
不是我在编写器中的代码抛出的,而是 Spring 的块事务提交逻辑抛出的,所以根本没有尝试重试。
Chunk Transaction Begin
Begin Retry loop in FaultTolerantChunkProcessor.write()
Writer logic in my Step
End Retry loop
Chunk Transaction Commit - Throws ObjectOptimisticLockingFailureException
当我尝试在编写器中显式抛出 ObjectOptimisticLockingFailureException
时,重试逻辑按预期完美运行。我的问题是:
- 如果在步骤中我的编写器代码没有抛出异常,但是在 Spring 批处理提交块事务时如何使重试逻辑起作用?
- 另一个奇怪的行为是,当我通过碰撞数据库中的版本列手动导致
ObjectOptimisticLockingFailureException
时,在步骤中注释了重试定义,该步骤的最终状态是 FAILED,这是预期的。但是在重试定义取消注释的情况下,该步骤的最终状态为 COMPLETE。这是为什么?
- How to make the retry logic work if the exception is not thrown from my writer code in the step, but by the time the chunk transaction is committed by Spring Batch?
这里有一个未解决的问题:https://github.com/spring-projects/spring-batch/issues/1826。解决方法是(尝试预测并)抛出在编写器中提交时可能发生的任何异常。这是您已经尝试过并在您说 When I tried to explicitly throw ObjectOptimisticLockingFailureException in my writer, the retry logic worked perfectly as expected
.
时确认有效的方法
- Another weird behavior is, when I manually cause the ObjectOptimisticLockingFailureException by bumping the version column in database, with the retry definition commented in the step, the final status of the step is FAILED which is expected. But with the retry definition uncommented, the final status of the step is COMPLETE. Why is that?
这与上一个问题有关,但是由不同的问题引起的:https://github.com/spring-projects/spring-batch/issues/1189. That said, it is ok to play with the version
field during a debugging session to understand how things work, but I would not recommend changing the version
column in your code. Spring Batch relies 在该列上大量使用其乐观锁定策略,预计不会在用户代码中更改该列的值,否则可能会发生意外行为。
在我的 Spring 批处理作业的其中一个步骤中,我正在尝试对其进行配置,以便在 ObjectOptimisticLockingFailureException
发生时可以重试该步骤,希望重试能够成功。
@Bean
public Step myStep(StaxEventItemReader<Response> staxEventResponseReader,
ItemWriter<Response> itemWriter,
ItemProcessor<? super Response, ? extends Response> responseProcessor) {
return stepBuilderFactory.get("myStep")
.<Response, Response>chunk(1)
.reader(staxEventResponseReader)
.processor(responseProcessor)
.writer(itemWriter)
//.faultTolerant().retryLimit(3).retry(Exception.class)
.build();
}
该步骤的 writer 逻辑非常简单:它尝试从数据库中读取一行,一旦找到该行,就会对其进行更新。我能够通过在 find 方法之后立即设置断点来重现 ObjectOptimisticLockingFailureException
,手动碰撞数据库中行的 version
列并提交它,然后恢复。
但是,在我的步骤中取消注释重试定义后,没有尝试重试。经过一些调试,似乎 Spring 重试逻辑在块的事务中;但是由于 ObjectOptimisticLockingFailureException
不是我在编写器中的代码抛出的,而是 Spring 的块事务提交逻辑抛出的,所以根本没有尝试重试。
Chunk Transaction Begin
Begin Retry loop in FaultTolerantChunkProcessor.write()
Writer logic in my Step
End Retry loop
Chunk Transaction Commit - Throws ObjectOptimisticLockingFailureException
当我尝试在编写器中显式抛出 ObjectOptimisticLockingFailureException
时,重试逻辑按预期完美运行。我的问题是:
- 如果在步骤中我的编写器代码没有抛出异常,但是在 Spring 批处理提交块事务时如何使重试逻辑起作用?
- 另一个奇怪的行为是,当我通过碰撞数据库中的版本列手动导致
ObjectOptimisticLockingFailureException
时,在步骤中注释了重试定义,该步骤的最终状态是 FAILED,这是预期的。但是在重试定义取消注释的情况下,该步骤的最终状态为 COMPLETE。这是为什么?
- How to make the retry logic work if the exception is not thrown from my writer code in the step, but by the time the chunk transaction is committed by Spring Batch?
这里有一个未解决的问题:https://github.com/spring-projects/spring-batch/issues/1826。解决方法是(尝试预测并)抛出在编写器中提交时可能发生的任何异常。这是您已经尝试过并在您说 When I tried to explicitly throw ObjectOptimisticLockingFailureException in my writer, the retry logic worked perfectly as expected
.
- Another weird behavior is, when I manually cause the ObjectOptimisticLockingFailureException by bumping the version column in database, with the retry definition commented in the step, the final status of the step is FAILED which is expected. But with the retry definition uncommented, the final status of the step is COMPLETE. Why is that?
这与上一个问题有关,但是由不同的问题引起的:https://github.com/spring-projects/spring-batch/issues/1189. That said, it is ok to play with the version
field during a debugging session to understand how things work, but I would not recommend changing the version
column in your code. Spring Batch relies 在该列上大量使用其乐观锁定策略,预计不会在用户代码中更改该列的值,否则可能会发生意外行为。