Loading...

Spring/Blog-V2 / / 2022. 3. 31. 01:25

스프링 53강. 양방향 매핑

반응형

 

 

연관관계

유저 - 코멘트 - 게시글

Post 1 : N Comment N : 1 User







우리 홈페이지에서 댓글만 보는 페이지는 없다.
게시글 상세보기 할 때 댓글이 나오지.

만약 관리자 페이지를 만들어서 모든 댓글을 봐야 할 때는 만들 수 있지만
댓글만 보는 페이지는 없다.




 Post를 SELECT 하는데 Comment를 가지고 올 수 없을 때 역방향 매핑을 해줘야 한다. 

@OneToMany 기본전략 LAZY


메인 페이지에서는 Post의 타이틀만 가져오는데 comment까지 다 가져오면 낭비가 너무 심하다.
Onetomany는 Lazy가 좋다!

 

스프링 기본전략 : 조인할 때 리스트 타입이 리턴되면 기본적으로 LAZY전략 사용
getter 호출될 때 조인


DB에 칼럼 만들지 말라고 알려줘야 한다.

mappedBy="연관관계 주인의 변수명"



Post를 SELECT 할 때 유저, 코멘트, 포스트 다 가져옴!!
내가 상세보기 할 때 코멘트가 필요 없다? 안 적으면 된다.

양방향 매핑은 참조키랑은 상관없는 것이다!

양방향 매핑을 하면 무한 로딩된다.


Post를 SELECT 하면 Post의 컬럼을 게터 때리고, 게터 때리다가 Comment 컬럼을 만나서
Comment 내부에 들어가서 Comment의 컬럼을 게터 때리고, 게터 때리다가

다시 Comment의 컬럼인 Post 오브젝트를
만나서 또 Post의 컬럼을 게터, 게터 때리고 무한 반복하게 된다.


그래서 이걸 메세지 컨버터에게 알려줘서 막아줘야 한다.


Comment 게터를 때릴 때 post 변수는 게터 때리지 말라고.

@JsonIgnoreProperties("post")


이 무한 참조는 메세지 컨버터가 json으로 변환하기 위해서 
게터를 계속 때림으로써 발생하는 것이다.

Comment 쪽에서 post 변수에 @JsonIgnore라고 걸어주면

Post 자체 게터를 때리지 말라는 건데
이렇게 하면 Comment만 SELECT 할 때도 post 변수를 게터 때리지 않는다.

 

그래서 JsonIgnoreProperties를 걸어서 내부에 있는 변수를 때리지 말라고 알려준다.

 

@AllArgsConstructor
@NoArgsConstructor
@Data
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Post { // N(드라이빙 테이블, FK의 주인)

    @JsonIgnoreProperties({ "password" }) // post 셀렉트할때만 제외, user 셀렉트할때는 나옴
    @JoinColumn(name = "userId")
    // Post가 Many니까 Many가 앞에 붙고 user가 One이니까 적음
    @ManyToOne(fetch = FetchType.EAGER)
    private User user;

    @JsonIgnoreProperties({ "post" }) // messageConverter에게 알려주는 어노테이션
    @OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE) // 연관관계의 주인의 변수명
    private List<Comment> comments;
}

 



처음에 메인 페이지에서는 Post와 User까지만 SELECT 하고 (EAGER)
메세지 컨버터가 데이터를 리턴해줄 때 json으로 변환하면서 Comment 게터를 때림으로써 
다시 쿼리를 실행하는 순서이다. (LAZY)

만약 Comment의 fetch 전략을 EAGER로 설정한다면
처음부터 포스트, 유저, 코멘트를 한방에 조인(left outer)해서 가져온다.

컬럼을 만드는 게 아니라, 코멘트까지 같이 가져오기 위해 모델에 추가해주는 것이다.


포스트를 SELECT 할 때 코멘트까지 필요할 때만 양방향 매핑 사용!!

SELECT * FROM post p
left outer join user u ON p.userId = u.id
left outer join comment c ON p.commentId = c.id;

 


 이거를 JPA가 대신해주는 것

 




SELECT *
FROM post p
INNER JOIN user u ON p.userId = u.id
INNER JOIN comment c ON p.id = c.postId
WHERE p.id = 1;


INNER 조인을 하니까 1번 게시글의 코멘트들이 나오는데
내가 2번 게시글이라 했을 때는 댓글이 없기 때문에 데이터를 돌려주지 않는다.
왜일까? 댓글 말고 포스트 정보들도 나와야 하지 않나? -> INNER 조인했기 때문이다.

포스트는 무조건 다 나와라!!
=> left outer join!!

그래서 스프링은 조인 기본전략이 LEFT OUTER 조인이다.


얘들이 INNER와 OUTER 조인을 구별해서 해줄 수 없다.

그냥 만들어진 알고리즘이기 때문이다.


결국 내가 직접 쿼리문을 만들어주는 게 좋다.


하지만 JPA가 어떤 조인을 쓰는지는 알아둬야 한다.
레프트 아우터 조인을 사용한다!

 

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 
반응형