[英]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.