Spring

ManyToOne 관계의 Jpa Stackoverflow 예외

기록만이살길 2021. 3. 14. 09:07
반응형

ManyToOne 관계의 Jpa Stackoverflow 예외

1. 질문(문제점):

내부에 하위 섹션을 포함 할 수있는 섹션이 있고 내부에 더 깊은 수준의 섹션이있을 수 있습니다. 실재:

@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 열에 null이있는 처음 두 개). 어떻게하려고하는지 :

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.StackOverflowError: 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=true SQL 결과 : 마지막 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=?

어디에 문제가 있습니까?

2. 해결방안:

사용 된 스택 추적 및 Lombok 어노테이션으로 판단 할 때 문제는의 재귀 호출과 관련이있을 수 있습니다 hashCode(). Lombok @DataequalshashCode메서드에 대한 구현을 생성 하며 기본적으로 이러한 구현은 parentchildren귀하의 경우를 포함하여 선언 된 모든 필드를 사용합니다 . 즉, "production"항목에 대한 해시 코드를 계산하려고하면 "subsectionOne"/ "subsectionTwo"에 대한 계산이 트리거되어 parent속성을 통해 "production"으로 돌아갑니다 .

필드에 hashCode추가 @EqualsAndHashCode.Exclude하여 구현 에서 세트를 제외하면 children문제가 해결됩니다.

65690025
반응형