问题
I'm working on spring-boot application with JPA. In the code I found a really suspicious part which does something like (simplified example, the code otherwise contains a lot of clutter):
entityRepository.findAll().parallel() // The findAll returns already a stream, it's a CrudRepository from Spring
.filter (...)
.map(e -> {
OtherDbObject other = service.getOtherDbObjectBasedOn(e);
boolean hasSomething = other.getProperties().stream() //properties is fetch type EAGER @OneToMany collection in OtherDbObject
.filter(...)
.findFirst()
.isPresent();
...
})
It seems the parallel
is causing whole lot of troubles including errors like:
jvm 1 | org.hibernate.AssertionFailure: bug adding collection twice
jvm 1 | at org.hibernate.engine.internal.StatefulPersistenceContext.addCollection(StatefulPersistenceContext.java:857)
jvm 1 | at org.hibernate.engine.internal.StatefulPersistenceContext.addInitializedCollection(StatefulPersistenceContext.java:896)
jvm 1 | at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:242)
jvm 1 | at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:221)
jvm 1 | at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:194)
jvm 1 | at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154)
jvm 1 | at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:249)
jvm 1 | at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:212)
jvm 1 | at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133)
jvm 1 | at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
jvm 1 | at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
jvm 1 | at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:88)
jvm 1 | at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:688)
jvm 1 | at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
jvm 1 | at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1991)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:570)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:739)
jvm 1 | at org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:924)
jvm 1 | at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:149)
jvm 1 | at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
jvm 1 | at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:88)
jvm 1 | at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:688)
jvm 1 | at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
jvm 1 | at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1991)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:570)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:252)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:566)
jvm 1 | at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:135)
jvm 1 | at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:277)
jvm 1 | at java.util.Spliterators$IteratorSpliterator.estimateSize(Spliterators.java:1821)
jvm 1 | at java.util.Spliterator.getExactSizeIfKnown(Spliterator.java:408)
jvm 1 | at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:497)
jvm 1 | at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
jvm 1 | at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
jvm 1 | at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
jvm 1 | at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
jvm 1 | at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
...
I would say it's at least suspicious to do something DB related in parallel
stream but I can't any evidence that it should be avoided.
I would appreciate any help in either explaining the error or finding solid evidence which proves that parallel streams with JPA inside are unsafe.
来源:https://stackoverflow.com/questions/44029856/using-jpa-objects-in-parallel-streams-with-spring