Announcement Announcement Module
Collapse
No announcement yet.
Spring-Data JPA + Spring-Batch + Java Config problem = TransactionRequiredException Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring-Data JPA + Spring-Batch + Java Config problem = TransactionRequiredException

    Hi!

    I'm trying to setup Spring-Batch with Spring-Data JPA but I'm having a lot of troubles... Well, lets start with versions I'm using:

    - Spring-Data JPA: 1.3.2.RELEASE
    - Spring-Batch: 2.2.0.RELEASE
    - Spring-Core: 3.1.2.RELEASE

    My ORM project using Spring-Data JPA is working as expected. It is being used as dependency of other projects and all IT tests are passing. The problem began when I tried to use it as a dependency of a new Chunk-Oriented Processing project that is using Spring-Batch.

    All processing is correctly done, but when it is time to persist the chunk by the ItemWriter, I get the following exception:

    Code:
    DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Participating in existing transaction
    DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Participating transaction failed - marking existing transaction as rollback-only
    DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Setting JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection@120942eb] rollback-only
    DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Participating transaction failed - marking existing transaction as rollback-only
    DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Setting JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection@120942eb] rollback-only
    DEBUG: org.springframework.batch.core.step.tasklet.TaskletStep - Applying contribution: [StepContribution: read=12, written=0, filtered=0, readSkips=0, writeSkips=0, processSkips=0, exitStatus=EXECUTING]
    DEBUG: org.springframework.batch.core.step.tasklet.TaskletStep - Rollback for RuntimeException: org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
    DEBUG: org.springframework.transaction.support.TransactionTemplate - Initiating transaction rollback on application exception
    org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
    	at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321)
    	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:106)
    	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
    	at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
    	at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    	at com.sun.proxy.$Proxy33.saveAndFlush(Unknown Source)
    	at br.com.receipt.feeder.job.init.writer.JpaProductItemWriter.write(JpaProductItemWriter.java:36)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:319)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    	at com.sun.proxy.$Proxy36.write(Unknown Source)
    	at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)
    	at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)
    	at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)
    	at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199)
    	at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
    	at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:395)
    	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
    	at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:267)
    	at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:77)
    My configuration files are:

    Code:
    @Configuration
    public class CvConfig {
        
        public static final String CV_DB_STEP = "cv_step";
        public static final String CV_DB_JOB = "cv_job";
        
        @Autowired
        private JobBuilderFactory jobs;
        
        @Autowired
        private StepBuilderFactory steps;
        
        @Autowired
        private ProductItemWriter writer;
        
        @Autowired
        private PlatformTransactionManager transactionManager;
        
        @Value("db/db-c&v*.txt")
        private Resource[] resources;
        
        @Bean(name = CV_DB_JOB)
        public Job cvJob() {
    	return this.jobs.get(CV_DB_JOB).flow(cvStep()).end().build();
        }
        
        @Bean
        public Step cvStep() {
    	return this.steps.get(CV_DB_STEP).<Object, Product> chunk(100)
    	        .reader(reader()).writer(this.writer)
    	        .transactionManager(this.transactionManager)
    	        .build();
        }
        
        public MultiResourceItemReader<Product> reader() {
    	return new DefaultProductItemReaderBuilder(new CvItemMapperContext(), this.resources[0]).build();
        }
        
    }
    Code:
    @Configuration
    @EnableBatchProcessing
    @Import({ RepositoryConfig.class, CvConfig.class })
    @ComponentScan(basePackages = { "br.com.receipt" })
    public class FeederConfig {
        
        @Bean
        public static PropertySourcesPlaceholderConfigurer properties() {
    	return new PropertySourcesPlaceholderConfigurer();
        }
        
        @Bean
        public TaskScheduler taskScheduler() {
    	return new ConcurrentTaskScheduler();
        }
        
        @Bean
        public JobRepository jobRepository() throws Exception {
    	return new SimpleJobRepository(
    	        new MapJobInstanceDao(),
    	        new MapJobExecutionDao(),
    	        new MapStepExecutionDao(),
    	        new MapExecutionContextDao());
        }
        
        @Bean
        public JobLauncher jobLauncher() throws Exception {
    	SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
    	jobLauncher.setJobRepository(jobRepository());
    	jobLauncher.afterPropertiesSet();
    	return jobLauncher;
        }
        
    }
    My ItemWriter (in this case ProductItemWriter) was implemented using Spring-Data's JpaRepository<Product, String>. The exception occur when the flush() is called.

    Code:
    @Component
    public class JpaProductItemWriter implements ProductItemWriter {
        
        private static final Logger LOGGER = LoggerFactory.getLogger(JpaProductItemWriter.class);
        
        private static final boolean DRY_RUN = false;
        
        private final ProductRepository repository;
        
        @Autowired
        public JpaProductItemWriter(ProductRepository repository) {
    	this.repository = repository;
        }
        
        @Override
        @Transactional
        public void write(List<? extends Product> items) {
    	for (Product product : items) {
    	    if (!this.repository.exists(product.getCode())) {
    		LOGGER.debug("Writting product: {}.", product);
    		
    		if (!DRY_RUN) {
    		    this.repository.saveAndFlush(product);
    		}
    	    } else {
    		LOGGER.debug("Product {} already in database.", product);
    	    }
    	}
        }
        
    }
    Thank you guys in advance.

  • #2
    Without pulling your code in to dig deeper, the glaring thing that should be changed is the removal of the @Transactional from the write method. Spring Batch manages the transactions as part of the framework and declaring methods as transactional like that causes known issues.

    Comment


    • #3
      Originally posted by mminella View Post
      Without pulling your code in to dig deeper, the glaring thing that should be changed is the removal of the @Transactional from the write method. Spring Batch manages the transactions as part of the framework and declaring methods as transactional like that causes known issues.
      Thank your Michael for your reply.

      I tried what you suggested but I'm still getting the same exception. I can provide you any code you want if it helps.

      Best regards,

      Comment


      • #4
        Originally posted by trein View Post
        Thank your Michael for your reply.

        I tried what you suggested but I'm still getting the same exception. I can provide you any code you want if it helps.

        Best regards,
        No one? I believe it is problem of compatibility between spring-data and spring-batch...

        Comment


        • #5
          Can you post a Github project that demonstrates your issue?

          Comment


          • #6
            Hi mminella,

            Thank you for your reply. Here is a sample project reproducing the issue: https://github.com/trein/spring-batch-data.
            In order to run the sample, execute br.com.sbd.feeder.FeederJobRunner.java with -Denvironment=development.
            It needs a MySQL database at localhost:3306 called receipt_dev (jdbc:mysql://localhost:3306/receipt_dev).

            Regards,

            Comment

            Working...
            X