I am currently working on Spring Batch (2.6.3) application and I am using JOOQ (3.14.15) to access MariaDB database (10.5.8).
So far I got working few jobs and got to the point where I am testing transactions.
I am trying to run tasklet which is to my understanding executed in transaction by default. I have made repository with simple insert which I annotated with @Transactional
. I have added Thread.sleep
and my "test case" is that I let Spring Batch execute my test tasklet and during sleep period I kill my application. I expected that there will be no record in T_FOO
table since I expected rollback of transaction but there is record in my T_FOO
table even though in BATCH_STEP_EXECUTION
my test step (after application shutdown) has status of STARTED
with END_TIME
set as null
- which I am guessing is representation that is expected when application gets shutdown while step is executing.
I am guessing that I did not setup correctly transaction management for Spring Batch and JOOQ or something along those lines? But it colud be wrong guess of course
Could someone please help me with this issue? I was trying to google how to properly setup JOOQ with Spring Batch but the only resource I could find was this one and I wrote jooq configuration inspired by that article and also I have tried copy paste configuration in article but it did not resolve my issue.
Thanks in advance for your time.
Tasklet test step
public Step testStep() {
return this.stepBuilderFactory.get(TEST_STEP)
.tasklet((stepContribution, chunkContext) -> {
final Integer batchId = JobUtils.getBatchId(chunkContext);
final LocalDateTime batchDate = JobUtils.getBatchDate(chunkContext);
importRepository.importBatch(batchId, batchDate);
/* Thread.sleep is here only for testing purposes - at this sleep I am shuting down application */
log.debug("Waiting start");
Thread.sleep(30000);
log.debug("Waiting end");
return RepeatStatus.FINISHED;
}).listener(loadingProcessingErrorListener)
.build();
}
Transactional(propagation = Propagation.REQUIRED)
public void importBatch(@NonNull Integer batchId, @NonNull LocalDateTime batchDate) {
/* simple insert select statement */
context.insertInto(T_FOO)
select(context.select(asterisk()).from(T_BAR))
execute();
}
Batch configuration
@Configuration
@RequiredArgsConstructor
public class BatchConfiguration extends DefaultBatchConfigurer {
private final JobRegistry jobRegistry;
private final DataSource dataSource;
@Override
@NonNull
@SneakyThrows
public JobLauncher getJobLauncher() {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository());
jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
@Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
postProcessor.setJobRegistry(jobRegistry);
return postProcessor;
}
@Override
@NonNull
public PlatformTransactionManager getTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
JOOQ configuration
@Configuration
@RequiredArgsConstructor
public class JooqConfiguration {
private final DataSource dataSource;
@Bean
public DataSourceConnectionProvider connectionProvider() {
return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));
}
@Bean
public DefaultDSLContext context() {
return new DefaultDSLContext(configuration());
}
public DefaultConfiguration configuration() {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(connectionProvider());
jooqConfiguration.setDataSource(dataSource);
jooqConfiguration.setSQLDialect(SQLDialect.MARIADB);
jooqConfiguration.setSettings(new Settings().withExecuteWithOptimisticLocking(true));
return jooqConfiguration;
}
}
Console log
2022-05-28 21:26:18.571 DEBUG 15656 --- [cTaskExecutor-1] s.o.p.c.p.a.j.i.ImportLoadingSteps : Starting loading import for Batch ID [1]
2022-05-28 21:26:18.607 INFO 15656 --- [cTaskExecutor-1] o.s.batch.core.job.SimpleStepHandler : Executing step: [testStep]
2022-05-28 21:26:18.861 DEBUG 15656 --- [cTaskExecutor-1] org.jooq.tools.LoggerListener : Executing query : insert into `t_foo`...
2022-05-28 21:26:18.875 DEBUG 15656 --- [cTaskExecutor-1] org.jooq.tools.LoggerListener : Affected row(s) : 1
2022-05-28 21:26:18.876 DEBUG 15656 --- [cTaskExecutor-1] s.o.p.c.p.a.j.i.ImportLoadingSteps : Waiting start
2022-05-28 21:26:23.759 INFO 15656 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED paused.
2022-05-28 21:26:23.783 INFO 15656 --- [ionShutdownHook] o.s.s.quartz.SchedulerFactoryBean : Shutting down Quartz Scheduler
2022-05-28 21:26:23.783 INFO 15656 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutting down.
2022-05-28 21:26:23.783 INFO 15656 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED paused.
2022-05-28 21:26:23.784 INFO 15656 --- [ionShutdownHook] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED shutdown complete.
2022-05-28 21:26:23.790 INFO 15656 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
Process finished with exit code -1
CodePudding user response:
You're doing this:
jooqConfiguration.set(connectionProvider());
But then, you're also needlessly doing this:
jooqConfiguration.setDataSource(dataSource);
The latter overrides the former, removing the TransactionAwareDataSourceProxy
semantics, and has no purpose otherwise, either. Just remove that call.