I'm working on Spring Batch with Spring Boot project. My question is, why HibernateTransactionManager and SessionFactory from LocalSessionFactoryBean are needed when I use HibernateItemWriter as below?
Application.java
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
import org.springframework.transaction.PlatformTransactionManager;
@SpringBootApplication
@EnableBatchProcessing
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Bean
public PlatformTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory(null));
return transactionManager;
}
@Bean
public SessionFactory sessionFactory(DataSource datasource) {
Properties properties = new Properties();
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
return new LocalSessionFactoryBuilder(datasource).scanPackages("hello")
.addProperties(properties)
.buildSessionFactory();
}
}
BatchConfiguration.java
import org.hibernate.SessionFactory;
import org.springframework.batch.core.Step;
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.item.ItemWriter;
import org.springframework.batch.item.database.HibernateItemWriter;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
import
org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.batch.item.file.transform.FieldExtractor;
import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.web.client.RestTemplate;
@Configuration
public class BatchConfiguration {
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Autowired
public RestTemplate restTemplate;
@Autowired
public PlatformTransactionManager tManager;
@Value("${file.name}")
public String fileName;
@Bean
@StepScope
public RestItemReader reader2() {
return new RestItemReader(restTemplate);
}
@Bean
public PersonItemProcessor processor() {
return new PersonItemProcessor();
}
@Bean
public HibernateItemWriter<Person> hibernateWriter(SessionFactory emf) {
HibernateItemWriter<Person> writer = new HibernateItemWriter<>();
writer.setSessionFactory(emf);
return writer;
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.transactionManager(tManager)
.<KarvyFundInfoModel, Person> chunk(2)
.reader(reader2())
.processor(new PersonItemProcessor())
.writer(hibernateWriter(null))
.build();
}
}
This is because if I didn't include it, and by getting SessionFactory from EntityManagerFactory using code as below
EntityManagerFactory.unwarp(SessionFactory.class);
I will get "no transaction is in progress" error. However, this is not the case when I use JpaItemWriter.
However based on my understanding on Spring Batch, in chunk processing, a default transaction manager is already provided.
Is it a must to provide HibernateTransactionManager and SessionFactory from LocalSessionFactoryBean(from hibernate) in order to use HibernateItemWriter?
And, what is the main difference between JpaItemWriter and HibernateItemWriter? I already did research regarding these two, Jpa is a specification on how to specify entity etc. by using annotation way and hibernate is one of the implementations of Jpa. Still, I'm not very clear on this. Is it hibernate has more features over default jpa? Such as SearchCriteria etc?
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.
One of the important goals of a batch processing framework is to read large amounts of data, perform some business processing/transformation and write out the result. Spring Batch Framework supports this bulk reading, processing and writing using three key interfaces: ItemReader, ItemProcessor and ItemWriter. 1.
ItemWriter that is using a JPA EntityManagerFactory to merge any Entities that aren't part of the persistence context. It is required that write (List) is called inside a transaction. The reader must be configured with an EntityManagerFactory that is capable of participating in Spring managed transactions.
Note the property commitInterval which is set to 1. This tells Spring Batch that the commit should happen after 1 element .i.e. writer will write 1 item at a time. Spring Batch comes with a simple utility class called CommandLineJobRunner which has a main () method which accepts two arguments.
why HibernateTransactionManager and SessionFactory from LocalSessionFactoryBean are needed when I use HibernateItemWriter
By default, if you provide a DataSource
bean, Spring Batch will use a DataSourceTransactionManager
to manage transactions. This transaction manager knows nothing about your JPA/Hibernate context. So the HibernateItemWriter
which is using the Hibernate Session
behind the scene is not "aware" of the ongoing transaction managed by the DataSourceTransactionManager
. Hence the error: no transaction is in progress
.
The HibernateTransactionManager
is what makes the Hibernate Session
participate in spring managed transactions.
what is the main difference between JpaItemWriter and HibernateItemWriter?
The JpaItemWriter
use JPA APIs (EntityManagerFactory
and EntityManager
)to write items. It does not use any JPA provider specific APIs. This makes it possible to switch the JPA provider without changing your writer.
The HibernateItemWriter
on the other side uses Hibernate specific APIs (SessionFactory
and Session
) and is specific to Hibernate only. This component can be useful for apps using hibernate directly without using JPA. You could have the same writer but for another JPA provider like OpenJpaItemWriter
or EclipseLinkItemWriter
which use specific APIs from these providers.
NB: There is a similar question to this one, I'm adding it here for reference: Transaction management with Spring Batch
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