Spring Batchのトランザクションをステップレベルからジョブレベルに変更する方法

Spring Batchでは、通常ステップがトランザクション境界となり、ステップ処理ごとにコミットが行われる。 チャンクの設定によって、一定件数処理するごと(1000件ごとなど)にコミットすることも可能。 大量データを処理する場合に、デフォルトでこの仕組みが備わっているのはありがたい。

しかし、ステップ間のデータに関連性があり、ステップごとにコミットしたくないという場合、Spring Batchではそれを実現する仕組みを提供していないため、自分で対応する必要がある。

ただ、必要なのは、ステップ実行の前に独自でトランザクションを開始する仕組みと、JobRepositoryFactoryBeanで既存トランザクションがあるか検証しているのをやめさせることの2点のみなので、意外と簡単に実現できる。

ジョブ起動時にトランザクションを開始するJobLauncher

ステップ実行前にトランザクションを開始するために適当なポイントはいくつかあると思われるが、JobLauncher#run@Transactional アノテーションをつけるのが手軽。

public class TransactionalJobLauncher extends SimpleJobLauncher {

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
        return super.run(job, jobParameters);
    }
}

バッチの設定

JobRepositoryでvalidateTransactionStatefalseにするのと、上で作ったJobLauncherを使うように設定する。

<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="validateTransactionState" value="false" />
</bean>
<bean id="jobLauncher" class="com.example.TransactionalJobLauncher" p:jobRepository-ref="jobRepository" />