Spring Batch JpaItemWriter vs HibernateItemWriter

2020-06-04 08:31发布

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?

1条回答
一夜七次
2楼-- · 2020-06-04 08:57

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

查看更多
登录 后发表回答