프로젝트 중 양방향 관계에 있어 순환참조가 반복됐다.
순환참조가 발생하여 결국 스택 오버 플로우에 빠지게 됐고 프로그램을 정상적으로 실행하지 못하게 된 상황.
이는 A가 B를 부르고 B가 A를 부르게 되면 나오는 상황이다. 끝없이 부르게 되니 스택 오버 플로우에 빠지게 된 셈.
이를 해결하기 위해 DTO에서 필요한 데이터만 응답하게끔 바꾸는 방법도 있지만, 스프링의 Jackson 라이브러리의
@JsonManagedReference와 @JsonBackReference 어노테이션을 사용하여 위 상황을 방지할 수도 있다.
먼저 순환참조가 일어났을 때 에디터 및 포스트맨에서 어떤 반응이 나오는지 살펴보자.
게시글 엔티티와 댓글 엔티티를 만들어 게시글 1 : 댓글 N 관계로 맵핑하였다.
// 게시글 엔티티
@OneToMany(mappedBy = "article")
private List<Comment> comments;
// 댓글 엔티티
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
private Article article;
서로 다른 클래스임을 알아두자.(적어놨지만..)
두 관계를 명시한 후에 먼저 게시글부터 간단히 작성했다.
게시글 작성은 잘 된다. 그 다음 해당 게시글 id를 맞추어 댓글을 작성해봤다.
포스트맨 상황은 이렇게 나왔다. 이클립스에서는 어떤 반응이 나왔을까?
무한히 서로 참조하여 결국 스택 오버 플로우에 빠져버렸다. 이를 방지하기 위해 위에서 언급했던 DTO에서 필요한 서로를 또 부르지 않게끔 가공하여 사용하는 방법도 있지만..
이번 글 제목처럼 @JsonManagedReference와 @JsonBackReference를 사용해보자.
// 게시글 엔티티
@OneToMany(mappedBy = "article")
@JsonManagedReference
private List<Comment> comments;
// 댓글 엔티티
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
@JsonBackReference
private Article article;
먼저 연관관계 주인 반대의 엔티티쪽에 @JsonManagedReference를 선언해준다. 그 다음 연관관계의 주인, 즉 N 쪽에 @JsonBackReference를 선언한다. 설명에 앞서 실행부터 해보자.
잘 됐다. 댓글을 여러 개 생성해보았다.
@JsonManagedReference와 @JsonBackReference는 양방향 관계에서 직렬화 방향을 설정하여 순환 참조를 막을 수 있도록 설계된 어노테이션이다. 즉 이 두 어노테이션은 순환 참조를 막기 위한 것.
@JsonManagedReference는 정상적으로 직렬화를 실행되고 @JsonBackReference은 직렬화가 되지 않도록 실행된다.
따라서 1 관계에 있는 쪽에서만 정상적으로 직렬화가 되기 때문에 1이 N를 부를 수 있게 되고, N 쪽에서는 직렬화가 막혔기 때문에 1을 부르지 않게 되어 순환 참조를 막을 수 있게 된다.
참고로 N 관계, 즉 연관 관계의 주인 쪽에서만 @JsonBackReference를 선언하고 반대쪽에선 @JsonManagedReference를 선언해주지 않아도 정상적으로 동작은 된다. 다만 서로의 관계를 확실하게 명시해주는게 중요할 것 같다.
// 게시글 엔티티
@OneToMany(mappedBy = "article")
private List<Comment> comments;
// 댓글 엔티티
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
@JsonBackReference
private Article article;
위 처럼 연관관계의 주인 쪽인 댓글(N관계)에서만 @JsonBackReference을 선언해주고 실행해보면
잘된다.
'Java > Spring' 카테고리의 다른 글
SpringBoot Bean 중복 처리(필드명 수정을 통한 방법) (0) | 2023.05.05 |
---|---|
Spring Boot + MyBatis (0) | 2023.04.13 |
@JoinColumn(mappedBy)과 연관 관계의 주인 (0) | 2022.12.09 |
Spring + MySQL 연동 (0) | 2022.11.24 |
@RequestParam과 @PathVariable (0) | 2022.11.22 |