ManyToOne关系中的Jpa ***异常

Posted

技术标签:

【中文标题】ManyToOne关系中的Jpa ***异常【英文标题】:Jpa *** exception in ManyToOne relation 【发布时间】:2021-01-12 18:40:16 【问题描述】:

我有部分,我可以在其中包含子部分,在其中我可以有更深层次的部分,甚至更远。实体:

@Data
@Table(name = "section")
@Entity
@NoArgsConstructor
public class Section 
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column
  private Long id;

  @Column private String title;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "parent_id")
  private Section parent;

  @JsonIgnore
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent")
  private Set<Section> children;

  public Section(Long id, String title, Section parent) 
    this.id = id;
    this.title = title;
    this.parent = parent;
  

出于测试目的,我将所有数据保存在 h2 数据库中。存储库类:

@Repository
public interface SectionRepository extends JpaRepository<Section, Long> 
  List<Section> findAllByParentId(Long parentId);

我在 h2 中有什么:

我只想找到这些没有父级的部分(前两个在 parent_id 列中为空)。我是如何做到的:

Section about = new Section(null, "about", null);
Section production = new Section(null, "production", null);

sectionRepository.save(about);
sectionRepository.save(production);

Section subsectionOne = new Section(null, "subsectionOne", production); // without adding
Section subsectionTwo = new Section(null, "subsectionTwo", production); // these two subsections
                                 sectionRepository.save(subsectionOne); // and saving them to db
                                 sectionRepository.save(subsectionTwo); // I don't receive any error on findAllByParentId(null) method call

sectionRepository.findAllByParentId(null); // action
java.lang.***Error: null
    at org.h2.util.ParserUtil.getSaveTokenType(ParserUtil.java:592) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.read(Parser.java:5092) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readIf(Parser.java:5011) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readTerm(Parser.java:4306) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readFactor(Parser.java:3343) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readSum(Parser.java:3330) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readConcat(Parser.java:3305) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readCondition(Parser.java:3108) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readExpression(Parser.java:3059) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelect(Parser.java:2952) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseQuerySub(Parser.java:2817) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelectUnion(Parser.java:2649) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseQuery(Parser.java:2620) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parsePrepared(Parser.java:868) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parse(Parser.java:843) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parse(Parser.java:815) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.prepareCommand(Parser.java:738) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.engine.Session.prepareLocal(Session.java:657) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.engine.Session.prepareCommand(Session.java:595) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:76) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:352) ~[h2-1.4.200.jar:1.4.200]
    at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:337) ~[HikariCP-3.4.5.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) ~[HikariCP-3.4.5.jar:na]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:151) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:198) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:162) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at java.base/java.util.HashMap.hash(HashMap.java:339) ~[na:na]
    at java.base/java.util.HashMap.put(HashMap.java:607) ~[na:na]
    at java.base/java.util.HashSet.add(HashSet.java:220) ~[na:na]
    at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:352) ~[na:na]
    at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:198) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:260) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:211) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:96) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at java.base/java.util.HashMap.hash(HashMap.java:339) ~[na:na]
    at java.base/java.util.HashMap.put(HashMap.java:607) ~[na:na]
    at java.base/java.util.HashSet.add(HashSet.java:220) ~[na:na]
    at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:352) ~[na:na]
    at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:198) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:260) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:211) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:96) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at java.base/java.util.HashMap.hash(HashMap.java:339) ~[na:na]
    at java.base/java.util.HashMap.put(HashMap.java:607) ~[na:na]
    at java.base/java.util.HashSet.add(HashSet.java:220) ~[na:na]

spring.jpa.show-sql=truesql结果:最后一个sql查询递归重复。

Hibernate: select section0_.id as id1_1_, section0_.parent_id as parent_i4_1_, section0_.title as title2_1_, section0_.titlelv as titlelv3_1_ from section section0_ left outer join section section1_ on section0_.parent_id=section1_.id where section1_.id is null
Hibernate: select children0_.parent_id as parent_i4_1_0_, children0_.id as id1_1_0_, children0_.id as id1_1_1_, children0_.parent_id as parent_i4_1_1_, children0_.title as title2_1_1_, children0_.titlelv as titlelv3_1_1_ from section children0_ where children0_.parent_id=?
Hibernate: select children0_.parent_id as parent_i4_1_0_, children0_.id as id1_1_0_, children0_.id as id1_1_1_, children0_.parent_id as parent_i4_1_1_, children0_.title as title2_1_1_, children0_.titlelv as titlelv3_1_1_ from section children0_ where children0_.parent_id=?

问题出在哪里?

【问题讨论】:

【参考方案1】:

从堆栈跟踪和使用的 Lombok 注释判断,问题可能与递归调用 hashCode() 有关。 Lombok 的@Data 将为equalshashCode 方法生成实现,默认情况下,这些实现将使用所有声明的字段,包括parentchildren。这意味着尝试计算“production”条目的哈希码将触发“subsectionOne”/“subsectionTwo”的计算,通过parent 属性返回“production”。

通过将@EqualsAndHashCode.Exclude 添加到children 字段从hashCode 实现中排除集合应该可以解决问题

【讨论】:

好的,谢谢。但我通过重写 equalshashCode 方法来仅检查 id 字段而不是类的所有字段。

以上是关于ManyToOne关系中的Jpa ***异常的主要内容,如果未能解决你的问题,请参考以下文章

为啥 JPA 默认使用 FetchType EAGER 来处理 @ManyToOne 关系

使用连接表将 JPA 双向 @ManyToOne 关系映射到多个表

JPA ManyToOne 关系:外键未存储在多方表中

Hibernate JPA - 没有填充ManyToOne关系

JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne

双向 JPA OneToMany/ManyToOne 关联中的“关联的反面”是啥?