I am discovering actually Spring and I am able to setup some jobs. Now, I would like to save my imported datas in a database using Hibernate/JPA and I keep getting this error :
14:46:43.500 [main] ERROR o.s.b.core.step.AbstractStep - Encountered an error executing the step javax.persistence.TransactionRequiredException: no transaction is in progress
I see that the problem is with the transaction. Here is my spring java config for the entityManager
and the transactionManager
:
@Configuration
public class PersistenceSpringConfig implements EnvironmentAware
{
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws Exception
{
// Initializes the entity manager
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
// Scans the database model
factoryBean.setPackagesToScan(EntiteJuridiqueJPA.class.getPackage().getName());
// Defines the Hibernate properties
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.show_sql", "false");
jpaProperties.setProperty("hibernate.format_sql", "false");
String connectionURL = "jdbc:h2:file:" + getDatabaseLocation();
jpaProperties.setProperty("hibernate.connection.url", connectionURL);
jpaProperties.setProperty("hibernate.connection.username", "sa");
jpaProperties.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
jpaProperties.setProperty("hibernate.dialect", H2Dialect.class.getName());
jpaProperties.setProperty("hibernate.hbm2ddl.auto", "create");
jpaProperties.setProperty("hibernate.hbm2ddl.import_files_sql_extractor", "org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor");
jpaProperties.setProperty("hibernate.hbm2ddl.import_files",
"org/springframework/batch/core/schema-drop-h2.sql,org/springframework/batch/core/schema-h2.sql");
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
@Bean
public PlatformTransactionManager transactionManager2() throws Exception
{
EntityManagerFactory object = entityManagerFactory().getObject();
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(object);
return jpaTransactionManager;
}
I am using the JpaItemWriter to store the datas in the database :
@Bean
public ItemWriter<EntiteJuridiqueJPA> writer()
{
JpaItemWriter<EntiteJuridiqueJPA> writer = new JpaItemWriter<EntiteJuridiqueJPA>();
writer.setEntityManagerFactory(entityManagerFactory.getObject());
return writer;
}
This is the code that causes the exception : javax.persistence.TransactionRequiredException: no transaction is in progress
Any idea to how to solve this problem?
[Edit] I am putting also the Job definition and the step definition. All my Spring configuration is written in Java.
@Configuration
@EnableBatchProcessing
@Import(PersistenceSpringConfig.class)
public class BatchSpringConfig
{
@Autowired
private JobBuilderFactory jobBuilders;
@Autowired
private StepBuilderFactory stepBuilders;
@Autowired
private DataSource dataSource;
@Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;
@Bean
public Step step()
{
return stepBuilders.get("step").<EntiteJuridique, EntiteJuridiqueJPA> chunk(5).reader(cvsReader(null))
.processor(processor()).writer(writer()).listener(processListener()).build();
}
@Bean
@StepScope
public FlatFileItemReader<EntiteJuridique> cvsReader(@Value("#{jobParameters[input]}") String input)
{
FlatFileItemReader<EntiteJuridique> flatFileReader = new FlatFileItemReader<EntiteJuridique>();
flatFileReader.setLineMapper(lineMapper());
flatFileReader.setResource(new ClassPathResource(input));
return flatFileReader;
}
@Bean
public LineMapper<EntiteJuridique> lineMapper()
{
DefaultLineMapper<EntiteJuridique> lineMapper = new DefaultLineMapper<EntiteJuridique>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(";");
lineTokenizer.setNames(new String[] { "MEGA_ENTITE", "PORTEFEUILLE", "MEGA_ENTITE", "Libellé" });
BeanWrapperFieldSetMapper<EntiteJuridique> fieldSetMapper = new BeanWrapperFieldSetMapper<EntiteJuridique>();
fieldSetMapper.setTargetType(EntiteJuridique.class);
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
}
@Bean
public Job dataInitializer()
{
return jobBuilders.get("dataInitializer").listener(protocolListener()).start(step()).build();
}
@Bean
public ItemProcessor<EntiteJuridique, EntiteJuridiqueJPA> processor()
{
return new EntiteJuridiqueProcessor();
}
@Bean
public ItemWriter<EntiteJuridiqueJPA> writer()
{
JpaItemWriter<EntiteJuridiqueJPA> writer = new JpaItemWriter<EntiteJuridiqueJPA>();
writer.setEntityManagerFactory(entityManagerFactory.getObject());
return writer;
// return new EntiteJuridiqueWriter();
}
@Bean
public ProtocolListener protocolListener()
{
return new ProtocolListener();
}
@Bean
public CSVProcessListener processListener()
{
return new CSVProcessListener();
}
@Bean
public PlatformTransactionManager transactionManager2() throws Exception
{
EntityManagerFactory object = entityManagerFactory.getObject();
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(object);
return jpaTransactionManager;
}
[EDIT] I am still stuck with this problem. I have followed the suggestions of @Sean Patrick Floyd and @bellabax by setting a transaction manager for the stepBuilders, but I still get the same exception. I have tested my entityManager independtly of spring-batch and I am able to store any data in the database.
But, when using the same entity manager with spring batch, I have this exception.
Anyone can give more insights how transactions are managed within spring batch? Thx for your help?
Spring supports both programmatic and declarative transaction management. EJBs require an application server, but Spring transaction management can be implemented without the need of an application server.
It loops through the list of people and, for each person, inserts that person into the BOOKINGS table by using the JdbcTemplate . This method is tagged with @Transactional , meaning that any failure causes the entire operation to roll back to its previous state and to re-throw the original exception.
You just need to create two transaction managers and inject them with the appropriate connection.
The problem is that you are creating a second transaction manager (transactionManager2), but Spring Batch is using another transaction manager for starting transactions. If you use @EnableBatchProcessing, Spring Batch automatically registers a transaction manager to use for its transactions, and your JpaTransactionManager never gets used. If you want to change the transaction manager that Spring Batch uses for transactions, you have to implement the interface BatchConfigurer. Take a look at this example: https://github.com/codecentric/spring-batch-javaconfig/blob/master/src/main/java/de/codecentric/batch/configuration/WebsphereInfrastructureConfiguration.java. Here I am switching the transaction manager to a WebspherUowTransactionManager, and in the same way you can switch the transaction manager to some other transaction manager. Here's the link to the blog post explaining it: http://blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With