Spring Batch ResourcelessTransactionManager messes with persistence.xml?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Spring Batch ResourcelessTransactionManager messes with persistence.xml?



I am working on an application and have been asked to implement a scheduled spring batch job. I have set up a configuration file where I set a @Bean ResourcelessTransactionManager but it seems to mess with the persistence.xml.


@Bean


ResourcelessTransactionManager


persistence.xml



There is already a persistence xml in an other module, there is no compilation error. I get a NoUniqueBeanDefinitionException when I am requesting a page that returns a view item.


NoUniqueBeanDefinitionException



This is the error:


Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: txManager,transactionManager
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:366)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:271)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.mypackage.services.MyClassService$$EnhancerBySpringCGLIB$$9e8bf16f.registryEvents(<generated>)
at com.mypackage.controllers.MyClassSearchView.init(MyClassSearchView.java:75)
... 168 more



Is there a way to tell spring batch to use the data source defined in the persistence.xml of the other module or maybe is this caused by something else?





Which transaction manager do you want to use? The one defined in persistence.xml or the ResourcelessTransactionManager you set up?
– Mahmoud Ben Hassine
Aug 7 at 16:38


ResourcelessTransactionManager





I want the ResourcelessTransactionManager for spring batch.
– Paris Karagiannopoulos
Aug 8 at 6:45




2 Answers
2



I created separate BatchScheduler java class as below and included it in BatchConfiguration java class. I am sharing both the classes. BatchConfiguration contains another jpaTransactionManager.


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.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@EnableScheduling
public class BatchScheduler

@Bean
public ResourcelessTransactionManager resourcelessTransactionManager()
return new ResourcelessTransactionManager();


@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(
ResourcelessTransactionManager resourcelessTransactionManager) throws Exception

MapJobRepositoryFactoryBean factory = new
MapJobRepositoryFactoryBean(resourcelessTransactionManager);

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;





BatchConfiguration contains another jpaTransactionManager.


import java.io.IOException;
import java.util.Date;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.transaction.PlatformTransactionManager;

import trade.api.common.constants.Constants;
import trade.api.entity.SecurityEntity;
import trade.api.trade.batch.item.processor.SecurityItemProcessor;
import trade.api.trade.batch.item.reader.NseSecurityReader;
import trade.api.trade.batch.notification.listener.SecurityJobCompletionNotificationListener;
import trade.api.trade.batch.tasklet.SecurityReaderTasklet;
import trade.api.vo.SecurityVO;

@Configuration
@EnableBatchProcessing
@EnableScheduling
@Import(OhlcMonthBatchConfiguration.class, OhlcWeekBatchConfiguration.class, OhlcDayBatchConfiguration.class, OhlcMinuteBatchConfiguration.class)
public class BatchConfiguration

private static final String OVERRIDDEN_BY_EXPRESSION = null;

/*
Load the properties
*/
@Value("$database.driver")
private String databaseDriver;
@Value("$database.url")
private String databaseUrl;
@Value("$database.username")
private String databaseUsername;
@Value("$database.password")
private String databasePassword;

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

@Autowired
private JobLauncher jobLauncher;

@Bean
public TaskScheduler taskScheduler()
return new ConcurrentTaskScheduler();


//second, minute, hour, day of month, month, day(s) of week
//@Scheduled(cron = "0 0 21 * * 1-5") on week days
@Scheduled(cron="$schedule.insert.security")
public void importSecuritySchedule() throws Exception

System.out.println("Job Started at :" + new Date());

JobParameters param = new JobParametersBuilder().addString("JobID",
String.valueOf(System.currentTimeMillis())).toJobParameters();

JobExecution execution = jobLauncher.run(importSecuritesJob(), param);

System.out.println("Job finished with status :" + execution.getStatus());


@Bean SecurityJobCompletionNotificationListener securityJobCompletionNotificationListener()
return new SecurityJobCompletionNotificationListener();





//Import Equity OHLC End

//Import Equity Start
// tag::readerwriterprocessor

@Bean
public SecurityReaderTasklet securityReaderTasklet()
return new SecurityReaderTasklet();


@Bean
@StepScope
public NseSecurityReader<SecurityVO> nseSecurityReader(@Value("#jobExecutionContext["+Constants.SECURITY_DOWNLOAD_FILE+"]") String pathToFile) throws IOException

NseSecurityReader<SecurityVO> reader = new NseSecurityReader<SecurityVO>();
reader.setLinesToSkip(1);
reader.setResource(new FileSystemResource(pathToFile));
reader.setLineMapper(new DefaultLineMapper<SecurityVO>()
setLineTokenizer(new DelimitedLineTokenizer()
setNames(new String "symbol", "nameOfCompany", "series", "dateOfListing", "paidUpValue", "marketLot", "isinNumber", "faceValue" );
);
setFieldSetMapper(new BeanWrapperFieldSetMapper<SecurityVO>()
setTargetType(SecurityVO.class);
);
);
return reader;



@Bean
public SecurityItemProcessor processor()
return new SecurityItemProcessor();


@Bean
public JpaItemWriter<SecurityEntity> writer()
JpaItemWriter<SecurityEntity> writer = new JpaItemWriter<SecurityEntity>();
writer.setEntityManagerFactory(entityManagerFactory().getObject());
return writer;

// end::readerwriterprocessor

// tag::jobstep
@Bean
public Job importSecuritesJob() throws IOException
return jobBuilderFactory.get("importSecuritesJob")
.incrementer(new RunIdIncrementer())
.listener(securityJobCompletionNotificationListener())
.start(downloadSecurityStep())
.next(insertSecurityStep())
.build();


@Bean
public Step downloadSecurityStep() throws IOException
return stepBuilderFactory.get("downloadSecurityStep")
.tasklet(securityReaderTasklet())
.build();


@Bean
public Step insertSecurityStep() throws IOException
return stepBuilderFactory.get("insertSecurityStep")
.transactionManager(jpaTransactionManager())
.<SecurityVO, SecurityEntity> chunk(100)
.reader(nseSecurityReader(OVERRIDDEN_BY_EXPRESSION))
.processor(processor())
.writer(writer())
.build();

// end::jobstep

//Import Equity End

@Bean
public DataSource dataSource()
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseDriver);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUsername);
dataSource.setPassword(databasePassword);
return dataSource;



@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()

LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setPackagesToScan("trade.api.entity");
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setJpaProperties(new Properties());
return lef;



@Bean
public JpaVendorAdapter jpaVendorAdapter()
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return jpaVendorAdapter;


@Bean
@Qualifier("jpaTransactionManager")
public PlatformTransactionManager jpaTransactionManager()
return new JpaTransactionManager(entityManagerFactory().getObject());


@Bean
public static PropertySourcesPlaceholderConfigurer dataProperties(Environment environment) throws IOException
String activeProfiles = environment.getActiveProfiles();
final PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:application-"+activeProfiles[0]+".properties"));
return ppc;

//// Import Security End





My Batch configuration class is similar with your BatchScheduler class. My problem is when an @Entity object is requested from the jpa. Before I setup the batch config everything worked fine. After the config the batch is working but the pages that bring back orm data are giving a NoUniqueBeanDefinitionException. It seems like the persistence.xml conflicts with my BatchConfig but I want my model to be able to see the persistence.xml configuration for the database and my BatchConfig the ResourcelessTransactionManager .
– Paris Karagiannopoulos
Aug 7 at 11:35






For txManager,transactionManager add @Qualifier (I have added it for my jpaTransactionManager. For batch steps I have provided the transaction manager name in steps(refer the above code). For Application methods use ` @Transactional("<your qualifier name>") public void doSomethingInBusinessData() ... `
– Sharad Gaikwad
Aug 7 at 12:18




Problem solved. There was a PlatformTransactionManager bean located in an other configuration file. I set it as @Primary and now the problem is fixed. Thanks everyone for the help.


PlatformTransactionManager


@Primary






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS