2

I have recently updated from spring boot 1.5 to 2.3.5 but I am facing some problems while persisting data. My application is spring batch, which reads, processes, and writes data to database, reader, and processor are fine, but the writer is giving problem. It's working fine with the 1.5 spring boot version. Following is the brief code :

BatchScheduler.Class

import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;

//@Configuration
@EnableScheduling
public class BatchScheduler {

  @Bean
  public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
  }

  @Bean
  public MapJobRepositoryFactoryBean  mapJobRepositoryFactory(
      ResourcelessTransactionManager txManager) throws Exception {

    MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager);
    factory.afterPropertiesSet();
    return factory;
  }

  @Bean
  public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
    return factory.getObject();
  }

  @Bean
  public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
    SimpleJobLauncher launcher = new SimpleJobLauncher();
    launcher.setJobRepository(jobRepository);
    return launcher;
  }
}
@Configuration
@EnableBatchProcessing
@Import({BatchScheduler.class})
public class LogBatchConfiguration {

  private static final Logger log = LoggerFactory.getLogger(LogBatchConfiguration.class);

  @Autowired private SimpleJobLauncher jobLauncher;

  @Autowired
  @Qualifier(value = "mainDataSource")
  public DataSource mainDataSource;

  @Autowired
  @Qualifier(value = "toolsDataSource")
  public DataSource toolsDataSource;

  @Autowired public StepBuilderFactory stepBuilderFactory;

  @Autowired public JobBuilderFactory jobBuilderFactory;

  @Autowired private RestTemplate restTemplate;

  @Qualifier(value = "createLocalSessionFactory")
  @Autowired
  private SessionFactory createLocalSessionFactory;

  @Qualifier(value = "createToolSessionFactory")
  @Autowired
  private SessionFactory createToolSessionFactory;

  @Bean
  RestTemplate restTemplate(RestTemplateBuilder builder) {
    RestTemplate restTemplate = new RestTemplate();
    List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
    for (HttpMessageConverter<?> converter : converters) {
      if (converter instanceof MappingJackson2HttpMessageConverter) {
        MappingJackson2HttpMessageConverter jsonConverter =
            (MappingJackson2HttpMessageConverter) converter;
        jsonConverter.setObjectMapper(new ObjectMapper());
        jsonConverter.setSupportedMediaTypes(
            ImmutableList.of(
                new MediaType(
                    "application", "json", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET),
                new MediaType(
                    "text", "javascript", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET)));
      }
    }
    return restTemplate;
  }

  @Bean
  public LocalSessionFactoryBean createLocalSessionFactory(
      @Qualifier("mainDataSource") DataSource dataSource) {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setPackagesToScan(
        new String[] {
          "com.abc.def..entities",
        
          "com.abc.entities"
        });
    factory.setHibernateProperties(hibernateVCommitProperties());
    return factory;
  }

  @Bean
  public LocalSessionFactoryBean createToolSessionFactory(
      @Qualifier("toolsDataSource") DataSource dataSource) {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setPackagesToScan(
        new String[] {
          "com.abc.def..entities",
        
          "com.abc.entities"
        });
    factory.setHibernateProperties(hibernateVCommitProperties());
    return factory;
  }

  
  @Scheduled(cron = "${server.cron}")
  public void SyncJobTrigger() throws Exception {
    if (log.isInfoEnabled()) {
     
    }
    JobParameters param =
        new JobParametersBuilder()
            .addString("JobID", String.valueOf(System.currentTimeMillis()))
            .toJobParameters();
    JobExecution execution = jobLauncher.run(populateServerDataJob(), param);
    if (log.isInfoEnabled()) {
      log.info("BATCH tools Server job finished with status: " + execution.getStatus());
    }
  }
  
  //--------------------------------- JOBS ----------------------------------------------
  @Bean
  public Job populateServerDataJob() throws Exception {
    return jobBuilderFactory
        .get("populateData")
        .start(serverRequestData()) // this step's writer is failing
        .next(a)
        .build();
  }

  @Bean
  @StepScope
  public HibernateCursorItemReader<Request> mylRequestReader() throws Exception {
    // returns reader and works fine as seen in logs, data is fetched
  }

  @Bean
  @StepScope
  public requestToServerProcessor requestToServerRequestProcessor() {
    return new requestToServerProcessor(mainDataSource);
  }

  // WRITER
  @Bean
  @StepScope
  public HibernateItemWriter<ServerRequestDetails> serverRequestWriter() {
    HibernateItemWriter<ServerRequestDetails> writer = new HibernateItemWriter();
    writer.setSessionFactory(createLocalSessionFactory(mainDataSource).getObject());
    return writer;
  }

  @Bean
  @JobScope
  public Step serverRequestData() throws Exception {
    return stepBuilderFactory
        .get("getServerRequestData")
        .<Request, ServerRequestDetails>chunk(100)
        .reader(mylRequestReader())
        .processor(requestToServerRequestProcessor())
        .writer(serverRequestWriter())
        .build();
  }
}
DataSourceConfiguration.class
@Configuration
public class DataSourceConfiguration {

  private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);
  @Value("${spring.datasource.usern}")
  private String insightsDbUser;

  @Value("${spring.datasource.pass}")
  private String insightsDbPass;

  @Value("${spring.datasource.url}")
  private String insightsDbConnection;

 
  @Value("${tools.datasource.user}")
  private String toolsDbUser

  @Value("${tools.datasource.pass}")
  private String toolsDbPass;

  @Value("${tools.datasource.url}")
  private String toolsDbConnection;

  @Bean(name = "mainDataSource")
  @Primary
  public DataSource mainDataSource() {

    DriverManagerDataSource dataSource = new DriverManagerDataSource();

    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl(insightsDbConnection);
    dataSource.setUsername(insightsDbUser);
    dataSource.setPassword(insightsDbPass);
    if (log.isInfoEnabled()) {
      //
    }
    return dataSource;
  }

  
  @Bean(name = "toolsDataSource")
  public DataSource vtoolsDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl(toolsDbConnection);
    dataSource.setUsername(toolsDbUser);
    dataSource.setPassword(toolsDbPass);
    if (log.isInfoEnabled()) {
      //
    }
    return dataSource;
  }
}

This works fine with 1.5 but gives below exception in 2.3.5 upgrade of spring boot:

javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:413)
    at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:3397)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1354)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1349)
    at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:95)
    at org.springframework.batch.item.database.HibernateItemWriter$$FastClassBySpringCGLIB$$1177da25.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at org.springframework.batch.item.database.HibernateItemWriter$$EnhancerBySpringCGLIB$$c0ff7bb9.write(<generated>)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:193)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:159)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:294)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:217)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy118.execute(Unknown Source)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:410)
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:136)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:319)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140)
    at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.execute(JobLauncherApplicationRunner.java:199)
    at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.executeLocalJobs(JobLauncherApplicationRunner.java:173)
    at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.launchJobFromProperties(JobLauncherApplicationRunner.java:160)
    at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:155)
    at org.springframework.boot.autoconfigure.batch.JobLauncherApplicationRunner.run(JobLauncherApplicationRunner.java:150)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:776)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)

I have searched some similar on StackOverflow but nothing helped.

I have made the following change in the properties file

spring.main.allow-bean-definition-overriding=true

because I was getting some "Cannot Create Bean, bean with the same name exists error" somewhere.

When the project builds, I do see following line :

2021-04-07 06:43:31.409  WARN 79404 --- [main] o.s.b.c.c.a.DefaultBatchConfigurer       : No transaction manager was provided, using a DataSourceTransactionManager
user124
  • 423
  • 2
  • 7
  • 26
  • You are using a `ResourceLessTransactionManager` which is basically stating you aren't using transactions. Thus things will fail. The error you got and which you "fixed" with allowing bean overrides is the actual problem. – M. Deinum Apr 07 '21 at 09:19
  • it is working fine in earlier version of 1.5 spring boot.What can I do? – user124 Apr 07 '21 at 10:31
  • It works by luck/accident. Why are you using that transactionamanger in the first place? You shouldn't need it as there is already one available, so remove it. – M. Deinum Apr 07 '21 at 11:15
  • which is the one already available? – user124 Apr 07 '21 at 12:09
  • i dont think that ResourceLessTransactionManager is being getting used, If u see last line of my question above, also i am using writer to write which is using DataSource to write. – user124 Apr 07 '21 at 12:26
  • You need to use the `HIbernateTransactionManager` and not the datasource or resourceless one. Neither will properly start a tx for hibernate. – M. Deinum Apr 07 '21 at 13:13
  • Reading your stack trace, you can also see that spring-batch is inherently triggering activities to do this in a transaction (see below) as it should to allow spring-batch commit intervals to proceed. It's clear that it's just not starting the right TYPE of transaction for the step to execute in. Having a Hibernate aware transaction manager per Deinum's suggestion makes the most sense. /// from your stack trace: at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) at org.....doInTransaction(TaskletStep.java:331) – Atmas Apr 07 '21 at 15:26
  • i will try that next week and update the thread with results – user124 Apr 09 '21 at 10:29
  • can you give any reference of how can i add HIbernateTransactionManager? Do i just need to create a bean or do i also need to specify it while running beans?Any reference example? – user124 Apr 11 '21 at 21:11
  • is it possible to change only BatchScheduler.Class to reflect changes, i can delete resourceless and replace by HIbernateTransactionManager ? – user124 Apr 11 '21 at 21:30
  • Does this answer your question? [how to fix no transaction is in progress in spring batch](https://stackoverflow.com/questions/53961468/how-to-fix-no-transaction-is-in-progress-in-spring-batch) – Mahmoud Ben Hassine Apr 19 '21 at 08:04

0 Answers0