순환 참조 발생
JPA는 디폴트로 맵핑된 데이터에 대해 FetchType.LAZY(게으른 불러오기)를 사용하게 된다.
예를 들어, User라는 Entity와 Acoount라는 Entity가 서로 양방향 참조 (1 :N)를 하고 있다고 해보자.
public class User{
@Id
privte long user_id;
..생략
@OneToMany(mappedBy = "user")
private List<Account> accounts;
}
public class Account{
@Id
private long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
JUtil을 통한 테스트 에서는 AccountRepository를 사용하여 return된 List의 사이즈가 1인지만 체크했다. 그 List에 포함된
Account를 꺼내서 따로 다른 작업을 하지 않았기 때문에 Account가 참조하고 있는 User Entity
는 전혀 건드리지 않은것이다.
하지만, Controller를 통해 Acoount Entity를 Response로 내보내고 브라우저 json형태로 뿌려주기 위해서는 Account entity 가 참조하고 있는 User entity도 함께 불러오게 된다.
그런데, 여기서 문제가 발생한다. User Entity 는 다시 Account Entity를 참조하기 때문에 또 Account Entity를 불러오는 것이다. Repository에서는 Account Entity한개를 Return 했지만 Controller 를 통해 Response 되어 Json으로 표시될 때는 이렇게 두 개의 entity 가 계속해서 서로를 불러오면서 페이지 가득 똑같은 데이터가 중복되어 노출된 것이다.
해결 방법
1. @JsonIgnore : 이 어노테이션을 붙이면 json 데이터에 해당 프로퍼티는 null로 들어가게 된다. 즉, 데이터에 아예 포함이 안되게 된다.
2. @JsonManagedReference 와 @JsonBackReference : 이 두개의 어노테이션이야 말로 순환참조를 방어하기 위한 Annotation이다. 부모 클래스에 @JsonManagedReference를, 자식 클래스측 에 @JsonBackReference 어노테이션을 추가해주면 된다.
3. DTO 사용 : 위와 같은 상황이 발생하게 된 주 원인은 양방향 매핑이기도 하지만, 더 정확하게는 entity 자체를 response로 리턴한데에 있다. entity 자체를 return하지 말고, dto 객체를 만들어 필요한 데이터만 옮겨 담아 client로 리턴하면 순환참조와 관련된 문제는 애초에 방어할 수 있다.
4. 맵핑 재설정 : 사람마다 다르지만 양방향 맵핑이 꼭 필요한지 다시 한번 생각해볼 필요가 있다. 만약 양쪽에서 접근할 필요가 없다면 단방향 맵핑을 하면 자연스레 순환참조가 해결된다.
출처 : https://m.blog.naver.com/writer0713/221587351970
'Study > JPA' 카테고리의 다른 글
[JPA] 벌크연산 (0) | 2022.03.30 |
---|---|
[JPA] Spring JPA CascadeType 종류 (0) | 2022.03.28 |
[JPA] DTO, Domain(Entity) (0) | 2022.03.26 |
Spring Data JPA에서 Query를 사용하는 방법 (0) | 2022.03.15 |
[JPA] Executing an update/delete query (0) | 2022.03.13 |
댓글