繁体   English   中英

在 ItemProcessor (Spring Batch) 中休眠没有会话

[英]Hibernate no session in ItemProcessor (Spring Batch)

在运行 Spring Batch 作业时,我在尝试访问 Hibernate 实体关系作为ItemProcessor一部分时遇到问题。 ItemProcessor是基于块的步骤的一部分。 据我所知ItemProcessor在事务中运行,因此应该能够延迟加载实体关系。

问题

作为ItemProcessor逻辑的一部分,我收到以下异常:

org.hibernate.LazyInitializationException: could not initialize proxy [org.powo.model.registry.Organisation#1] - no Session
        at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
        at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
        at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
        at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
        at org.powo.model.registry.Organisation$HibernateProxy$OFnEWoXa.getIdentifier(Unknown Source)
        at org.powo.model.solr.BaseSolrInputDocument.build(BaseSolrInputDocument.java:39)
        at org.powo.model.solr.TaxonSolrInputDocument.<init>(TaxonSolrInputDocument.java:67)
        at org.powo.model.Taxon.toSolrInputDocument(Taxon.java:1091)
        at org.powo.job.reindex.TaxonToSolrInputDocumentProcessor.process(TaxonToSolrInputDocumentProcessor.java:20)
        at org.powo.job.reindex.TaxonToSolrInputDocumentProcessor.process(TaxonToSolrInputDocumentProcessor.java:13)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:126)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:303)
        at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:202)
        at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:272)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:66)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:136)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:308)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:141)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)

这是供参考的ItemProcessor (在toSolrInputDocument逻辑中是遍历实体关系的地方):

@Component
public class TaxonToSolrInputDocumentProcessor implements ItemProcessor<Taxon, SolrInputDocument> {
  @Autowired
  private ApplicationContext context;

  @Override
  public SolrInputDocument process(Taxon item) throws Exception {
    return item.toSolrInputDocument(context);
  }
}

我使用org.springframework.batch.item.database.HibernatePagingItemReader作为读者。

我试过的

我已经尝试了以下但没有一个解决方案可以防止上述错误:

  • 使用JpaPagingItemReader而不是HibernatePagingItemReader但这仍然有同样的问题
  • 使用@Autowired获取SessionFactory ,然后围绕遍历实体关系的代码执行openSession / closeSession

由于数据模型的原因,我无法在一个查询中获取所有关系,因此我需要使用有状态会话(尽管我想获取一些!)。

AFAIK 每一步(读取、处理、写入)都会为处理的每个块创建一个单独的事务,因此如果您的ItemReader没有初始化处理器或ItemReader器中所需的关联,您将遇到此错误,因为实体分离当事务提交后实体管理器关闭时。 我不知道是否可以告诉 Spring 在整个过程中保留一个实体管理器,但是如果您想依赖延迟初始化,则必须弄清楚这一点。

我建议您确保使用正确的连接提取,以避免延迟初始化的需要,即select t from Taxon t join fetch t.organization o ,或者甚至更好,使用 DTO 方法,以便您没有根本不关心延迟初始化。

我认为这是Blaze-Persistence Entity Views的完美用例。

我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义的模型之间轻松映射,例如类固醇上的 Spring Data Projections。 这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

使用 Blaze-Persistence Entity-Views 的用例的 DTO 模型可能如下所示:

@EntityView(Taxon.class)
public interface TaxonDto {
    @IdMapping
    Long getId();
    String getName();
    OrganizationDto getOrganization();

    @EntityView(Organization.class)
    interface OrganizationDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

查询是将实体视图应用于查询的问题,最简单的只是按 id 查询。

TaxonDto a = entityViewManager.find(entityManager, TaxonDto.class, id);

Spring Data 集成允许您几乎像 Spring Data Projections 一样使用它: https : //persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<TaxonDto> findAll(Pageable pageable);

最好的部分是,它只会获取实际需要的状态!

我现在已经解决了这个问题 - 最后JpaPagingItemReader解决了这个问题。 我不确定为什么它以前不起作用,尽管我确实发现设置任何类型的taskExecutor似乎会立即破坏延迟加载。

暂无
暂无

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

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