kagamihogeの日記

kagamihogeの日記です。

spring-batch内でトランザクションつかってるあたりを知る

背景

spring-batchは内部的に随所でメタテーブルなどトランザクション処理がある。軽くソースコード見た限りでは@Transactionalがついてるわけでもないのにトランザクションってどうやって実行してるのかな? と知りたくなったのでソースを見た。

しらべたソースコード

pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-batch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
    </dependencies>

JobRepository

JobRepositoryメタデータの永続化の責務がある。で、このクラスのメソッドに対してAOPTransactionInterceptorを設定している。

public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean<JobRepository>, InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
                // ..略
        initializeProxy();
    }

    private ProxyFactory proxyFactory;
    private void initializeProxy() throws Exception {
            proxyFactory = new ProxyFactory();
            TransactionInterceptor advice = new TransactionInterceptor(transactionManager,
                    PropertiesConverter.stringToProperties("create*=PROPAGATION_REQUIRES_NEW,"
                            + isolationLevelForCreate + "\ngetLastJobExecution*=PROPAGATION_REQUIRES_NEW,"
                            + isolationLevelForCreate + "\n*=PROPAGATION_REQUIRED"));
            // ..略
            proxyFactory.addAdvice(advice);
            proxyFactory.setProxyTargetClass(false);
            proxyFactory.addInterface(JobRepository.class);
            proxyFactory.setTarget(getTarget());

こんな感じにInitializingBean#afterPropertiesSetのタイミングでAOPを仕込んでいる。対象メソッドのパターンはTransactionInterceptorの引数のプロパティとして渡しているけど若干見辛いので、以下のDEBUGログな感じで設定している。

(略)[*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT] 
(略)[create*] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE] 
(略)[getLastJobExecution*] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_SERIALIZABLE] 

Step

対して、Stepの各chunkに対するトランザクションはというと、以下のようにTransactionTemplateを使用している。

public class TaskletStep extends AbstractStep {
    @Override
    protected void doExecute(StepExecution stepExecution) throws Exception {
                // ... 略
                try {
                    result = new TransactionTemplate(transactionManager, transactionAttribute)
                    .execute(new ChunkTransactionCallback(chunkContext, semaphore));
                }
                catch (UncheckedTransactionException e) {
                    // Allow checked exceptions to be thrown inside callback
                    throw (Exception) e.getCause();
                }