I recently migrated my spring boot/batch Java application from spring-boot/spring-framework (respectively) 1.xx/4.xx to => 2.xx/5.xx (2.2.4/5.2.3 to be specific). The problem is something is definitely wrong (in my opinion) with the transaction/entity manager, as when the .saveAll()
method is called from the JpaRepository
class of my database persistance layer, it jumps into the SpringAOP framework/libarary code and into a infinite loop. I see it returning a "DefaulTransaction" object from a method (invoke()). My application on 1.xx/4.xx when it worked, would return the actual ArrayList here of my entities. I am using spring-boot-starter
, spring-boot-starter-web
, spring-boot-starter-data-jpa
, spring-boot-starter-batch
, and hibernate
/ hibernate-envers
/ hibernate-entitymanager
(also of course many other dependencies, let me know if you would like me to list them).
After some research, I'm finding people are saying that Spring Batch @EnableBatchProcessing
annotation sets up a default transaction manager, which if I'm using JPA could be causing issues. Reference: https://github.com/spring-projects/spring-boot/issues/2363
wilkinsona suggested defining this Bean in my @Configuration
class:
@Bean
public BatchConfigurer batchConfigurer(DataSource dataSource, EntityManagerFactory entityManagerFactory) {
return new BasicBatchConfigurer(dataSource, entityManagerFactory);
}
I'm getting an error when I do this because its saying the BasicBatchConfigurer()
has protected access. What is the best way to instantiate this?
I also saw some people saying removing the @EnableBatchProcessing
annotation fixes the persistance to database issue, but when I remove this, I lose the ability to Autowire my JobBuilderFactory and StepBuilderFactory . Is there a way to remove the annotation and get these objects in my code so I can at-least test if this works? Sorry, I'm not completely a master with Spring Batch/Spring.
In my @Configuration
class, I am using the PlatformTransactionManager
. I am setting up my JobRepository something like this.:
@Bean
public JobRepository jobRepository(PlatformTransactionManager transactionManager,
@Qualifier("dataSource") DataSource dataSource) throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDataSource(dataSource);
jobRepositoryFactoryBean.setTransactionManager(transactionManager);
jobRepositoryFactoryBean.setDatabaseType("POSTGRES");
return jobRepositoryFactoryBean.getObject();
}
I can provide any other information if needed. Another question is - if I was using the same code basically, transaction manager, entity manager etc.. how was old my code working on 1.xx? Could I have a wrong dependency somewhere in my pom.xml such that my new migrated code is using a wrong method or something from the wrong dependency?
By default, @EnableBatchProcessing
configures Spring Batch to use a DataSourceTransactionManager
if you provide a DataSource
. This transaction manager knows nothing about your JPA context. So if you want to use a JPA repository to save data, you need to configure Spring Batch to use a JpaTransactionManager
.
Now in order to provide a custom transaction manager, you need to register a BatchConfigurer
and override the getTransactionManager()
method, something like:
@Bean
public BatchConfigurer batchConfigurer(DataSource dataSource) {
return new DefaultBatchConfigurer(dataSource) {
@Override
public PlatformTransactionManager getTransactionManager() {
return new JpaTransactionManager();
}
};
}
This is explained in the Configuring A Job section and in the Javadoc of @EnableBatchProcessing
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.