Spring Batch JpaItemWriter与HibernateItemWriter以及为什么使用HibernateItemWriter时为什么需要HibernateTransactionManager

时间:2018-09-16 12:21:22

标签: java spring hibernate spring-boot spring-batch

我正在使用Spring Boot项目进行Spring Batch。 我的问题是,当我使用HibernateItemWriter时,为什么需要LocalSessionFactoryBean的HibernateTransactionManager和SessionFactory?

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();
}
}

这是因为如果我不包含它,并通过使用以下代码从EntityManagerFactory获取SessionFactory

EntityManagerFactory.unwarp(SessionFactory.class);

我将收到“没有正在进行的交易”错误。但是,当我使用JpaItemWriter时,情况并非如此。

但是根据我对Spring Batch的理解,在块处理中,已经提供了默认的事务管理器。

是否必须从LocalSessionFactoryBean(来自hibernate)提供HibernateTransactionManager和SessionFactory才能使用HibernateItemWriter?

而且,JpaItemWriter和HibernateItemWriter之间的主要区别是什么? 我已经做过关于这两个方面的研究,Jpa是关于如何通过使用批注方式指定实体等的规范,而hibernate是Jpa的实现之一。不过,我对此并不十分清楚。休眠是否比默认的jpa具有更多功能?例如SearchCriteria等?

1 个答案:

答案 0 :(得分:2)

  

为什么当我使用HibernateItemWriter时需要LocalSessionFactoryBean的HibernateTransactionManager和SessionFactory

默认情况下,如果提供DataSource bean,Spring Batch将使用DataSourceTransactionManager来管理事务。该事务管理器对您的JPA /休眠上下文一无所知。因此,在后台使用休眠HibernateItemWriter的{​​{1}}并不“意识到” Session管理的正在进行的事务。因此,错误:DataSourceTransactionManager

no transaction is in progress是使Hibernate HibernateTransactionManager参与春季托管事务的原因。

  

JpaItemWriter和HibernateItemWriter的主要区别是什么?

Session使用JPA API(JpaItemWriterEntityManagerFactory)来编写项目。它不使用任何JPA提供程序特定的API。这样就可以在不更改编写器的情况下切换JPA提供程序。

另一方面,EntityManager使用特定于Hibernate的API(HibernateItemWriterSessionFactory),并且仅特定于Hibernate。该组件对于直接使用休眠而不使用JPA的应用程序很有用。您可能拥有相同的作者,但是对于另一个JPA提供程序(例如SessionOpenJpaItemWriter),它们使用这些提供程序中的特定API。


注意:这有一个类似的问题,我在此添加以供参考:Transaction management with Spring Batch