The documentation is not very clear about the role of PlatformTransactionManager
in steps configuration.
First, stepBuilder.tasklet
and stepBuilder.chunk
requires a PlatformTransactionManager
as second parameter while the migration guide says it is now required to manually configure the transaction manager on any tasklet step definition (...) This is only required for tasklet steps, other step types do not require a transaction manager by design..
More over, in the documentation the transactionManager
is injected via a method parameter:
/**
* Note the TransactionManager is typically autowired in and not needed to be explicitly
* configured
*/
But the transactionManager
created by Spring Boot is linked to the DataSource
created by Spring Boot based on spring.datasource.url
. So with autoconfiguration, the following beans works together: dataSource
, platformTransactionManager
, jobRepository
. It makes sense for job and step executions metadata management.
But unless readers, writers and tasklet works with this default DataSource
used by JobOperator
, the auto configured transactionManager
must not be used for the steps configuration. Am I right ?
Tasklets or a chunk oriented steps will often need another PlatformTransactionManager
:
- if a step writes data in a specific db it needs a specific
DataSource
(not necessarily declared as bean otherwise theJobRepository
will use it) and a specificPlatformTransactionManager
linked to thisDataSource
- if a step writes data in a file or send message to a MOM, the
ResourcelessTransactionManager
is more appropriate. This useful implementation is not mentioned in the documentation.
As far as I understand, the implementation of PlatformTransactionManager
for a step depends on where the data are written and has nothing to do with the transactionManager
bean used by the JobOperator
Am I right ?
Example:
var builder = new StepBuilder("step-1", jobRepository);
PlatformTransactionManager txManager = new ResourcelessTransactionManager();
return builder.<Input, Output> chunk(10, txManager)
.reader(reader())
.processor(processor())
.writer(writer()/*a FlatFileItemWriter*/)
.build();
or
@SpringBootApplication
@EnableBatchProcessing
public class MyJobConfiguration {
private DataSource dsForStep1Writer;
public MyJobConfiguration(@Value("${ds.for.step1.writer.url"} String url) {
this.dsForStep1Writer = new DriverManagerDataSource(url);
}
// reader() method, processor() method
JdbcBatchItemWriter<Output> writer() {
return new JdbcBatchItemWriterBuilder<Output>()
.dataSource(this.dsForStep1Writer)
.sql("...")
.itemPreparedStatementSetter((item, ps)->{/*code*/})
.build();
}
@Bean
Step step1(JobRepository jobRepository) {
var builder = new StepBuilder("step-1", jobRepository);
var txManager = new JdbcTransactionManager(this.dsForStep1Writer);
return builder.<Input, Output> chunk(10, txManager)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
// other methods
}
Is that correct ?