我们的Spring Batch应用程序在重新启动失败的作业后,再次处理相同的记录,导致重复的行,我们想要了解如何避免这种情况。
启动批处理作业的Spring Integration轮询器配置为每隔几个小时运行一次。当它第二次运行时,作业参数将是相同的,但如果前一次运行失败(例如,由于DataTruncation异常),Spring Batch将不会抱怨作业已经完成。
在失败时,已经处理了数十万条记录并将其从源表复制到目标表。当作业在后续运行时,相同的行将被复制到目标表,从而导致重复。因此,似乎作业没有恢复,而是从一开始就重新开始。
Spring Batch数据库是Derby(基于文件),这是在应用程序启动时设置的,并且在实际应用程序的重新启动之间不会保持状态(因为可以使用相同的参数再次运行作业)。但是,在一个应用程序运行中,状态得以维护。例如,如果作业成功完成,则下次轮询器运行异常将被抛出,因为作业(带有这些参数)已经完成。
我们的工作定义如下:
<batch:job id="publisherJob" >
<batch:step id="step1">
<batch:tasklet >
<batch:chunk reader="itemReader" processor="itemProcessor"
writer="itemWriter" commit-interval="${...}" />
</batch:tasklet>
<batch:listeners>
...
</batch:listeners>
</batch:job>
<bean id="itemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource" />
<property name="sql" value="select ${...} from ${...} where ${...}" />
<property name="rowMapper" ref="rowMapper" />
</bean>
WHERE子句包含ORDER BY。
我们的理解是,Spring Batch将保留处理失败的状态并从该点开始(如果源表中的错误已得到修复),从而防止重复行。必须为此配置什么?
由于
答案 0 :(得分:1)
Spring Batch维护状态,因为它记住处理了多少记录,而不是具体记录了哪些记录。因此,您可以保证项目的顺序在运行期间可以重现,这样,如果我们在运行1中处理100条记录并且失败,当我们跳过运行2中的前100条记录时,那些是要跳过的100条记录。您没有为JdbcCursorItemReader
提供配置,但我的假设是您没有在SQL中使用订单。如果要重新启动,则需要某种方法来保证项目的顺序。在SQL中使用order by是实现此目的的最简单方法(如果需要,还可以使用过程指示器模式)。