[강의] 자바 ORM 표준 JPA 프로그래밍 - 기본편 05 연관관계 매핑 기초
자바 ORM 표준 JPA 프로그래밍 - 기본편 강의
김영한님의 인프런 강의(자바 ORM 표준 JPA 프로그래밍 - 기본편) 을 수강하면서 강의 내용을 일부 발췌해 요약한 글.
섹션 5 연관관계 매핑 기초
양방향 연관관계
테이블 연관관계에서는 외래키만으로 두 테이블이 연결된다. (양쪽으로 join할 수 있다.)
그러나 좀 전의 객체 연관 관계에서 멤버는 팀 객체를 가지고 있으나 팀은 멤버를 가지고 있지 않기 때문에 팀 객체에서 멤버를 찾을 수 없다. 객체 연관관계에서는 팀에서도 멤버를 가지고 있어야 팀과 멤버가 양방향으로 연관될 수 있다.
양방향 매핑이 과연 좋은가? -> 객체의 경우 양방향이면 신경쓸 부분이 많아 단방향이 좋다. 추후 설명할 예정
mappedBy?
객체가 테이블 간 연관관계를 맺는 차이를 이해해야 한다. 객체의 연관관계는 단방향의 연관관계 2개(팀->멤버, 멤버->팀)인 반면 테이블의 연관관계는 양방향의 연관관계(외래키) 1개이다.
멤버의 팀을 변경한다고 생각해보자. 멤버 객체의 팀을 변경해야할 지 팀 객체의 멤버를 변경해야할 지 정해야 한다. 이를 연관관계의 주인이라고 한다. 연관관계의 주인만이 외래 키를 관리(등록, 수정)할 수 있으며 주인이 아닌쪽은 읽기만 가능하다. 주인은 mappedBy를 사용할 수 없으며, 주인이 아닌 경우 mappedBy 속성으로 주인을 지정해주어야 한다. 결론적으로 외래키가 있는 곳을 주인으로 정해야 한다. 예시에서는 Member.team이 연관관계의 주인이 된다.
DB입장에서 외래키가 있는 곳이 무조건 N(다)이고, 외래키가 없는 곳이 1이다. 결국 N(다) 쪽이 연관관계의 주인이 되어야 깔끔하다. 비즈니스 상 중요한 개념이 연관관계의 주인이 되는 것이 아님을 주의하자. 단순히 N(다) 쪽이 연관관계의 주인이라고 생각하면 된다.
양방향 매핑 시 연관관계의 주인에 값을 입력하지 않는 실수가 가장 잦다. 꼭 연관관계의 주인에 값을 입력하도록 주의하자. 참고로 객체지향 관점에선 양방향에 모두 값을 입력해주는 것이 적절하다. 연관관계의 주인에만 값을 입력하는 건 여러 문제를 야기할 수 있다. 먼저, flush, clear로 영속성 컨텍스트를 완전히 초기화하지 않은 경우 DB에서 조회하지 않고 1차 캐시에 있는 값이 로딩되므로 값이 반영되지 않을 수 있다. 뿐만 아니라, 테스트 케이스를 작성하는 경우에도 원하는 대로 수행되지 않을 수 있다.
결론적으로 양방향 매핑 시에는 순수 객체 상태를 고려해 양쪽 모두 값을 세팅을 해주는 것이 바람직하다. -> 연관관계 편의 메소드를 생성하자!
1
2
3
4
public void setTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
Member에서 setTeam 으로 team을 세팅하는 시점에 Team의 getMembers에도 add해주면 하나만 호출해주더라도 양쪽이 세팅된다. 연관관계 편의 메서드는 1,N 모두 무관하나 한쪽에만 구현해두는 것이 바람직하다. 덧붙여, 연관관계 편의 메소드처럼 setter에 로직이 들어가는 경우 setTeam보다는 changeTeam 등으로 이름을 바꿔주는 것을 권장한다. 더 복잡한 로직은 책을 참고하자.
양방향 매핑 시 toString을 호출하는 경우 계속 서로를 호출하기 때문에 무한루프에 걸릴 수 있다. 뿐만 아니라 Lombok, JSON 생성 라이브러리도 마찬가지이다. 웬만하면 toString을 빼서 쓰고, 컨트롤러에서는 엔티티를 절대 반환하지 마라. 엔티티를 반환하는 대신 단순히 값만 있는 DTO(Data Transfer Object)로 변환해 반환하는 것을 추천한다.
정리
설계 시에는 반드시 단방향 매핑만으로 완료한다. 단방향 매핑만으로도 연관관계는 이미 매핑이 완료되며, 양방향 매핑은 반대 방향으로의 조회 기능이 추가된 것 뿐이다. 양방향 매핑이 객체 입장에서는 신경쓸 일이 많아 좋지만은 않으나 JPQL에서 역방향으로 탐색할 일이 많고 편의상 실무에서 필요할 일이 꽤 있다. 결론적으로는 단방향 매핑을 잘해야 하고, 양방향은 테이블에 영향을 주지 않으므로 필요할 때 천천히 추가해도 된다. 단방향을 최대한 활용하자. 또한, 양방향 매핑 시 연관관계의 주인을 정하는 기준은 비즈니스 로직이 아닌 외래 키의 위치이다. 값을 넣어줄 때는 주인과 주인이 아닌 곳 모두에 넣어주어야 하며, 연관관계 편의 메서드를 생각하자.
- 실습 예제에서 회원이 주문 정보를 가지고 있을 필요가 있을까? 비즈니스 로직에 맞게 연결관계를 적절하게 끊어내는 것도 매우 중요하다.