简体   繁体   English

如何在 Spring Batch 中使用 HibernateCursorItemReader

[英]How to use HibernateCursorItemReader in spring batch

In a spring batch job, I have a step in which I want to read data by chunk from the database using Hibernate, process it and write it back to the database.在 spring 批处理作业中,我有一个步骤,我想使用 Hibernate 从数据库中按块读取数据,处理它并将其写回数据库。 Right now I'm having some trouble setting up the reader :现在我在设置阅读器时遇到了一些麻烦:

@EnableBatchProcessing
@Configuration
@ComponentScan(basePackages = {"com.x.y.z.database", "com.x.y.p.database"}, excludeFilters={
        @ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE, value=ConfigHelperMail.class)})
@EntityScan(basePackages = {"com.x.y.z.database", "com.x.y.p.database"})
@EnableJpaRepositories({"com.x.y.z.database", "com.x.y.p.database"})
public class BatchConfiguration {
    @Autowired
    public JobBuilderFactory jobs;
    @Bean
    public Job job(CustomJobListener listener,
                     @Qualifier("step1") Step step1,
                     @Qualifier("step2") Step step2,
                     @Qualifier("step3") Step step3) {
        return jobs.get("SimpleJobName")
                .incrementer(new RunIdIncrementer())
                .preventRestart()
                .listener(listener)
                .start(step1)
                .next(step2)
                .next(step3)
                .build();
    }
}

In step1 writer I save the data to the database using Hibernate :step1 writer 中,我使用 Hibernate 将数据保存到数据库中:

@Entity
@Table(name = "tmp_z_stepone")
public class StepOneEntity {
    @Id
    @Column(name = "reference")
    private String reference;
    /** Other properties and getters and setters **/
}

@Component
public class StepOneWriter implements ItemWriter<StepOneEntity> {
    @Autowired
    private StepOneService stepOneService;
    @Override
    public void write (List<? extends StepOneEntity> items) throws WriterException {
        stepOneService.saveMany(items);
    }
}

StepOneService is annotated with @Service and it uses a DAO interface that extends CrudRepository<StepOneEntity, String> and its saveMany method just uses the save method from CrudRepository<StepOneEntity, String> . StepOneService使用@Service注释,它使用扩展CrudRepository<StepOneEntity, String>的 DAO 接口,其saveMany方法仅使用CrudRepository<StepOneEntity, String>save方法。

Step 2第2步

@Component
public class StepOne {
    @Autowired
    private StepTwoReader reader;
    @Autowired
    private StepTwoProcessor processor;
    @Autowired
    private StepTwoWriter writer;
    @Bean
    @JobScope
    @Qualifier("step2")
    public Step step2() throws ReaderException {
        return stepBuilderFactory.get("step2")
                .<StepOneEntity, StepTwoEntity>chunk(10)
                .reader(reader.read())
                .processor(processor)
                .writer(writer)
                .build();
    }
}

@Component
public class StepTwoReader {
    public ItemReader<OutputControleFormat> read () throws ReaderException {
        HibernateCursorItemReader itemReader = new HibernateCursorItemReader();
        itemReader.setQueryString("from tmp_z_stepone");
        itemReader.setUseStatelessSession(true);
        return itemReader;
    }
}

I think I'm missionf some session/ORM configuration but I don't know where, the error is below :我想我正在执行一些会话/ORM 配置,但我不知道在哪里,错误如下:

org.springframework.batch.item.ItemStreamException: Failed to initialize the reader
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:147) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:96) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.step.item.ChunkMonitor.open(ChunkMonitor.java:114) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:96) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:310) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:197) ~[spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at com.sun.proxy.$Proxy110.execute(Unknown Source) [na:na]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:392) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) [spring-batch-core-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at com.sun.proxy.$Proxy107.run(Unknown Source) [na:na]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:211) [spring-boot-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:227) [spring-boot-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:123) [spring-boot-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:117) [spring-boot-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at com.cdn.oxc.signature.ApplicationConfig.main(ApplicationConfig.java:33) [classes/:na]
Caused by: java.lang.NullPointerException: null
    at org.springframework.batch.item.database.HibernateItemReaderHelper.createQuery(HibernateItemReaderHelper.java:141) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.item.database.HibernateItemReaderHelper.getForwardOnlyCursor(HibernateItemReaderHelper.java:125) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.item.database.HibernateCursorItemReader.doOpen(HibernateCursorItemReader.java:185) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:144) ~[spring-batch-infrastructure-3.0.8.RELEASE.jar:3.0.8.RELEASE]
    ... 46 common frames omitted

HibernateCursorItemReader implements the InitializingBean interface, which means that Spring will call its afterPropertiesSet on container initialization if it is declared as a bean. HibernateCursorItemReader实现了InitializingBean接口,这意味着如果将Spring声明为bean, afterPropertiesSet在容器初始化时调用afterPropertiesSet However, in your case, the HibernateCursorItemReader is not declared as a bean in the application context, it is wrapped in a class ( StepTwoReader ) then created with reader.read() . 但是,在您的情况下, HibernateCursorItemReader在应用程序上下文中未声明为Bean,而是包装在一个类( StepTwoReader )中,然后使用reader.read()创建。

If you declare the HibernateCursorItemReader as a bean with your current code in your read method, you should get an IllegalStateException with message: "A SessionFactory must be provided". 如果使用read方法中的当前代码将HibernateCursorItemReader声明为Bean,则应获得IllegalStateException并显示消息:“必须提供SessionFactory”。 You actually need to configure a SessionFactory for your Hibernate reader. 实际上,您实际上需要为Hibernate阅读器配置一个SessionFactory

Another option is to use the HibernateCursorItemReaderBuilder which will ensure the reader is correctly configured. 另一个选择是使用HibernateCursorItemReaderBuilder ,它将确保阅读器已正确配置。

@StepScope
@Slf4j
@Component
public class CursorItemReader extends HibernateCursorItemReader<ItemEntity> {


    public CursorItemReader(EntityManagerFactory entityManagerFactory,
                            @Value("#{stepExecution}")StepExecution stepExecution) {

       
        this.setName("CursorItemReader");
        this.setSessionFactory(entityManagerFactory.createEntityManager().unwrap(org.hibernate.Session.class).getSessionFactory());
        this.setQueryString("from ItemEntity");
        this.setUseStatelessSession(true);
        this.setFetchSize(5);
    }

    @Override
    public ItemEntity read() throws Exception {
        ItemEntity item = this.doRead();
        return item;
    }

}

You can also refer- https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#HibernateCursorItemReader您也可以参考- https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#HibernateCursorItemReader

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM