背景
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
はメタデータの永続化の責務がある。で、このクラスのメソッドに対してAOPでTransactionInterceptor
を設定している。
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(); }