java - Spring Batch JpaItemWriter vs HibernateItemWriter 以及为什么在使用 HibernateItemWriter 时需要 HibernateTransactionManager

标签 java spring hibernate spring-boot spring-batch

我正在使用 Spring Boot 项目开发 Spring Batch。 我的问题是,当我如下使用 HibernateItemWriter 时,为什么需要来自 LocalSessionFactoryBean 的 HibernateTransactionManager 和 SessionFactory?

应用程序.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();
}
}

批量配置.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的理解,在 block 处理中,已经提供了一个默认的事务管理器。

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

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

最佳答案

why HibernateTransactionManager and SessionFactory from LocalSessionFactoryBean are needed when I use HibernateItemWriter

默认情况下,如果您提供一个DataSource bean,Spring Batch 将使用一个DataSourceTransactionManager 来管理事务。该事务管理器对您的 JPA/Hibernate 上下文一无所知。因此,在后台使用 Hibernate SessionHibernateItemWriter 不会“意识到”由 DataSourceTransactionManager 管理的正在进行的事务。因此出现错误:没有正在进行的事务

HibernateTransactionManager 使 Hibernate Session 参与 spring 管理的事务。

what is the main difference between JpaItemWriter and HibernateItemWriter?

JpaItemWriter 使用 JPA API(EntityManagerFactoryEntityManager)写入项目。它不使用任何 JPA 提供程序特定的 API。这使得在不更改编写器的情况下切换 JPA 提供程序成为可能。

另一方面,HibernateItemWriter 使用 Hibernate 特定的 API(SessionFactorySession)并且仅特定于 Hibernate。该组件对于直接使用 hibernate 而不使用 JPA 的应用程序很有用。您可以拥有相同的编写器,但使用来自这些提供程序的特定 API 的另一个 JPA 提供程序,例如 OpenJpaItemWriterEclipseLinkItemWriter


注意:有一个类似的问题,我在这里添加它以供引用:Transaction management with Spring Batch

关于java - Spring Batch JpaItemWriter vs HibernateItemWriter 以及为什么在使用 HibernateItemWriter 时需要 HibernateTransactionManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52354066/

相关文章:

java - 重命名 openconnection() 还是剪掉它?

java - 需要有关使用 Maven 创建 jar 的提示

java - 无法使用maven项目创建可运行的jar文件

java - Spring简单示例: where create list of beans in JavaConfig?

java - 强制急切加载其他延迟加载的属性

hibernate - 在域类初始化中使用编码器

java - '0' 在 Java 中有什么作用?

java - 从数据库中获取大值

java - 随机子矩阵

java - 将 Java int[][] 的神秘 bytea 表示形式转换回数组(Hibernate)