【发布时间】:2021-01-09 20:39:22
【问题描述】:
我有一个 spring-batch 作业,它使用 RepositoryItemReader 从数据库中读取,然后将结果转换为 Map,然后将结果写入 elasticsearch。它工作正常,虽然有点慢。所以现在我想添加一个池大小为 4 的 taskExecutor 以加快速度:
return stepBuilders.get("search-export").<AbstractEntityDefinition, Map<String, Object>>chunk(nemesisSearchProperties.getExport().getChunkSize())
.reader(reader)
.processor(processor)
.writer(writer)
.stream(reader)
.transactionAttribute(transactionAttribute)
.listener(chunkSessionReplicatorExecutionListener)
.listener(new NemesisChunkLoggingListener(indexName + " search export", nemesisSearchProperties.getExport().getChunkSize()))
.taskExecutor(searchExportTaskExecutor).throttleLimit(4) // <-- I add this
.build();
但是,当我添加任务执行器时,我得到了这个:
java.lang.NullPointerException
at org.hibernate.internal.util.collections.IdentityMap.entryArray(IdentityMap.java:162)
at org.hibernate.internal.util.collections.IdentityMap.concurrentEntries(IdentityMap.java:58)
at org.hibernate.engine.internal.StatefulPersistenceContext.forEachCollectionEntry(StatefulPersistenceContext.java:1135)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes(AbstractFlushingEventListener.java:193)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
看着IdentityMap我可以看到这个:
(1) if ( entryArray == null ) {
(2) entryArray = new Map.Entry[ map.size() ];
final Iterator<Entry<IdentityKey<K>, V>> itr = map.entrySet().iterator();
int i = 0;
while ( itr.hasNext() ) {
final Entry<IdentityKey<K>, V> me = itr.next();
(3) entryArray[i++] = new IdentityMapEntry( me.getKey().key, me.getValue() ); // Here entryArray is NULL!!!
}
}
异常发生在第 (3) 行,其中entryArray 为空。而且我想知道它是如何做到的,因为entryArray 在第 (1) 行被检查为空并在第 (2) 行初始化。
任何想法将不胜感激。
【问题讨论】:
-
从您分享的内容来看,Spring Batch 方面没有任何问题。由于这个 NPE 发生在 Hibernate 的代码中,我会让 hibernate 专家帮助你。
-
@MahmoudBenHassine 你能指导我如何根据 Christian 的建议编写一个每个线程都有一个单独的休眠会话的阅读器
-
我认为我们不需要这样做。项目阅读器不应该关心线程是如何分配的。它是驱动进程并决定读卡器应该由单个线程还是多个线程调用的步骤。如果项目阅读器不是线程安全的并且应该在多线程步骤中使用,那么它可以用
SynchronizedIteamStreamReader装饰。 -
也就是说,从
RepositoryItemReader的Javadoc 中,我看到:This implementation is thread-safe between calls to open(ExecutionContext), but remember to use saveState=false if used in a multi-threaded client (no restart available)。您是否尝试过设置 saveState=false?我之所以问,是因为我无法从您的部分堆栈跟踪中看到在处理执行上下文时是否发生异常。 -
嗨@MahmoudBenHassine 确实我没有设置saveState=false。现在我添加了它,我在另一个地方得到了另一个空指针异常:gist.github.com/ptahchiev/b63d909fc8bb048d95df1c7376be43fe
标签: hibernate jpa orm spring-batch hibernate-mapping