[자바 ORM표준 JPA 프로그래밍-기본편] 다양한 연관관계 매핑

songh·2024년 11월 21일

Spring

목록 보기
46/51

연관관계 매핑시 고려해야할 3가지는 다중성, 단방향-양방향, 연관관계의 주인이다.

다중성

JPA에서 나온 어노테이션은 모두 데이터베이스와 매핑하기 위해서 나온 것이라고 믿으면 된다. 아래 3가지만 주로 사용한다.
🔎 다대일 @ManyToOne
🔎 일대다 @OneToMany
🔎 일대일 @OneToOne

단방향, 양방향

테이블과 객체, 이 두 가지만 놓고 생각해보자. 테이블은 외래키 하나만 가지고도 join으로 쿼리를 만들면 방향이 어떻든 서로 조회가 가능하다. 하지만 객체는 각 클래스마다 참조용 필드를 가지고 있어야 한쪽으로 참조가 가능하다. 객체의 경우 각자 참조용 필드를 들고 있으면 단방향이 2개여서 양방향이라고도 부른다.

연관관계의 주인

테이블은 외래키 하나만 가지고 조인을 통해서 서로의 테이블을 확인할 수 있지만, 객체는 양방향으로 A➡️B, B➡️A 처럼 참조를 각자 들고 있어야 한다. 테이블과 객체를 매핑하기 위해서는 객체쪽에서 A가 외래키를 관리할지, B가 외래키를 관리할지 정해야하는데, 이 둘중 누가 연관관계의 주인이 되더라도 테이블의 외래키쪽은 관리가 되어야 한다. INSERT, UPDATE, DELETE 등등 쿼리가 날아가야 할 것 아닌가. 따라서 연관관계의 주인 = 외래키를 관리하는 곳이라고 보면 된다. 반면 반대편은 해당 객체의 DATA만 조회가능하고 관리를 할 수 없는 읽기전용임을 알 수 있다.

  • 다대일 양방향 : 외래키가 있는 곳이 연관관계의 주인

  • 일(Team)대다(Member) 단방향 : 권장하지 않는 방법, 다대일 양방향을 사용
    (Team객체에서 수정했음에도 Member(외래키가 있는 테이블)에서 UPDATE쿼리가 나가기 때문-생각지도 못한 곳에서 쿼리가 나가서 혼동된다.)
    일쪽이 연관관계의 주인이 되지만, 테이블에서는 항상 다(N)쪽에 외래키를 들고 있기 때문에 객체에서 관리(삽입,삭제,수정 등)하더라도 테이블에서는 반대편 테이블에서 쿼리가 나가는 특이한 구조가 된다. 따라서 일(1)쪽에 @JoinColumn를 설정해야한다.

  • 일대다 양방향 : 공식적으로 존재X, 다대일 양방향을 사용

  • 일대일 관계 : 주 테이블이나 대상 테이블(주 테이블이 아닌 곳을 말함) 중 외래키를 어디에 둘지 선택할 수 있다. 주 테이블에 외래키를 둬도 되고, 대상 테이블에 외래키를 둬도 된다. 객체와 매핑되면 DB에 외래키에 유니크 제약조건이 추가된다.

  • 일대일 단방향 : 다대일 단방향 매핑과 유사하게 객체를 설정하면 된다.

  • 일대일 양방향 : 다대일 양방향 매핑과 유사하게 외래키가 있는 곳을 연관관계 주인으로 설정, 주인이 아닌 곳은 mappedBy 적용한다.

  • 일대일 정리 [주 테이블에 외래키] : 객체지향 개발자는 선호하는 방법이다. JPA 매핑이 편리해지고 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 조회가 편리하다. 하지만 단점은 값이 없으면 외래키에 null을 허용한다는 문제가 있다.

  • 일대일 정리 [대상 테이블에 외래키] : DB개발자는 선호하는 방법이다. 주 테이블과 대상 테이블을 일대일에서 일대다로 변경할때 테이블 구조를 유지할 수 있다. 대상 테이블이 N이 되고 다쪽에 외래키가 존재하기 때문에 개발자가 다시 수정할 필요가 없기 때문이다. 단점은 프록시 기능 한계로 인해 지연로딩으로 설정해놓아도 항상 즉시로딩이 된다. 이유는 Member과 Locker가 1:1이고 Locker에만 MEMER_ID 외래키를 가지고 있다고 생각해보자. 그러면 Member가 존재하는지 찾으려면 Locker로 가서 일일이 하나씩 멤버를 뒤져야하기 때문이다.

  • 다대다 관계 : 관계형 데이터베이스에는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 중간 테이블을 두어 일대다, 다대일 관계로 풀어내야한다. 다대다 매핑은 편리해보이지만 실무에서 절대 사용해서는 안되고 연결 테이블이 단순 연결만 하고 끝낼 수 없는 복잡한 매핑구조다. 다대다 매핑은 연결 테이블을 엔티티로 승격해서 한계를 극복해야 한다. @ManyToMany

✅ (추천)중간테이블 - PK, FK 구조 [방법1]

id(PK), Member_id(FK), Product_id(FK)
PK는 왠만하면 의미없는 값으로 설정하는게 좋으며 더 유연하게 사용할 수 있다.

✅ 중간테이블 - PK, FK 구조 [방법2]

Member_id(PK, FK), Product_id(PK, FK)

@JoinColumn - 외래키 매핑시 사용하는 어노테이션

@ManyToOne

@OneToMany

0개의 댓글