【发布时间】:2021-12-01 05:51:09
【问题描述】:
我在运行 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
由于数据模型的原因,我无法在一个查询中获取所有关系,因此我需要使用有状态会话(尽管我想获取一些!)。
【问题讨论】:
-
您能否使用调用该过程的方法更新您的样本。如果在事务中调用它并且实体没有在该持久上下文中分离,则没有理由会出现延迟初始化异常。
-
它被 Spring Batch 调用,作为批处理作业中基于块的步骤的一部分。
-
您如何以及从何处管理应用程序的数据库事务?你是@Transactional 注释吗?理想情况下,当 spring 启动一个数据库事务时,一个持久的上下文会与之绑定。在该方法中,您需要使您的对象附加到该持久上下文(有几种方法可以这样做)。如果您尝试获取列表项,则在退出该事务方法之前,您不应该得到惰性异常。
-
因为这是作为 Spring Batch 基于块的步骤的一部分运行的,所以我认为 Spring 正在管理事务 - 它肯定是在从数据库读取时。文档说事务在读取开始时打开,在读取开始时关闭,在写入提交时关闭 - 因此它应该在处理器运行时打开(因此我很困惑)。我认为这可能与 XML 配置有关 - 我在一个新的 Spring Boot 项目上对此进行了测试,它按预期工作。
标签: java spring hibernate spring-batch