프로그래밍/java, spring

@JsonIgnore, @JsonBackReference, @JsonManagedReference의 차이 및 FetchType.LAZY와의 관계

브래드 킴 2023. 1. 21. 23:09
728x90

@JsonIgnore

@JsonIgnore는 사실 OneToMany <> ManyToOne 등 객체간 참조관계를 원천적으로 차단하는데 사용되기 위해 설계된 것은 아니다.

이 어노테이션은 말그대로 return 해주는 json에서 지정된 컬럼을 제외하겠다는 어노테이션이다.

그래서, password와 같은 민감한 정보가 return값으로 나가지 않도록 사용되기도 하고,

json에서 제외되다 보니, 순환참조를 끊는데 사용되기도 하는 것이다.

@JsonManagedReference과 @JsonBackReference

두 어노테이션은 두순환참조를 끊기 위해 설계되었다. @JsonManagedReference은 조회된 데이터를 정상적으로 serialize(직렬화)시킨다. 즉, 참조되는 데이터를 가져온다는 것이다. @JsonbackaReference 어노테이션은 serialize되지 않도록 설계되어 데이터를 참조하지 않게 된다.

그래서 자식객체에 선언되는 @JsonBackReference 컬럼의 경우엔 entity에서 바로 json return값으로 받아볼수가 없다. 그러나, 쿼리로 데이터를 조회는 해오므로 별도의 mapping 객체를 통해 값을 받아오거나, getter를 통해 값을 꺼내어 @Transient어노테이션이 붙은 별도의 컬럼에 값을 set해주는 방법을 사용하면된다.

@JsonManagedReference에서 FetchType.LAZY는 무의미

@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
@JsonManagedReference
private List<Post> posts = new ArrayList<>();

OneToMany의 경우 기본설정이 LAZY이므로 위처럼 굳이 명시할 필요는 없다. 그런데, JsonManagedReference가 지정되면, 쿼리는 lazy로 작동하지 않게 된다.

JsonIgnore였다면, findAll()을 실행했을때 EAGER라면 N+1번의 쿼리가 실행된다. LAZY라면 참조객체를 코드상에서 사용하기 전까지 참조테이블에 쿼리를 날리지 않는다. 쿼리는 이렇게 lazy와 eager에 따라 달라지지만, jsonignore이기에 둘다 json으로 해당객체를 return하지는 않는다.

그러나, JsonManagedReference로 지정이 되면, Lazy이든 Eager이든 모두 N+1의 쿼리를 날리고 Json으로 값을 리턴하게 된다. FetchType보다 JSON 직렬화(serialize)에 대한 설정이 우선하게 되는듯 하다. 그래서 이 경우엔 lazy + findAll 조합을 사용하기 보다는 fetch join을 사용하는 것이 쿼리 효율성에 좋을 것이다.

728x90