티스토리 뷰



일대일 [1:1]

  • 일대일 관계는 그 반대도 일대일이다.

  • 일대일 관계는 특이하게 주 테이블이나 대상 테이블 중에 외래 키를 넣을 테이블을 선택 가능하다.

    • 주 테이블에 외래 키 저장

    • 대상 테이블에 외래 키 저장

  • 외래 키에 데이터베이스 유니크 제약조건 추가되어야 일대일 관계가 된다.

일대일 - 주 테이블에 외래 키 단방향

  • 회원이 딱 하나의 락커를 가지고 있는 상황이다. 반대로 락커도 회원 한명만 할당 받을 수 있는 비즈니스 적인 룰이 있고, 이때, 둘의 관계는 일대일 관계이다.

  • 이 경우 멤버를 주 테이블로 보고 주 테이블 또는 대상 테이블에 외래 키를 저장할 수 있다. 단, 유니크 제약조건을 추가한 상태에서만.

  • 다대일[N:1] 단방향 관계 매핑과 JPA 어노테이션만 달라지고, 거의 유사하다.

일대일 - 주 테이블에 외래 키 양방향

  • 다대일[N:1] 양방향 매핑 처럼 외래키가 있는 곳이 연관관계의 주인이다.

  • JPA @OneToOne 어노테이션으로 일대일 단방향 관계를 매핑하고, @JoinColumn을 넣어준다.

    • @JoinColumn은 Default 값이 있긴 하지만 지저분하게 들어간다. name을 정해주자.

    • 여기까지만 매핑하면 단방향 관계이고

      @Entity
      public class Member {
        ...
             
         @OneToOne
         @JoinColumn(name = "locker_id")
         private Locker locker;

        ...
      }
  • 반대편에 mappedBy를 적용시켜주면 일대일 양방향 관계 매핑이 된다.

    • mappedBy = "locker" 는 Member엔티티에 있는 Locker 필드와 매핑 되었다는 것을 의미.

    • 이 member 필드는 읽기 전용 필드이다.

      @Entity
      public class Locker {
        ...
             
         @OneToOne(mappedBy = "locker")
         private Member member;
      }

일대일 - 대상 테이블에 외래 키 단방향

  • 일대일관계에서 대상 테이블에 외래 키를 저장하는 단방향 관계는 JPA에서 지원하지 않는다.

일대일 - 대상 테이블에 외래 키 양방향

  • 일대일 주 테이블에 외래 키 양방향 매핑을 반대로 뒤집었다고 생각하면 된다. 매핑 방법은 같다.

  • 주 테이블은 멤버 테이블이지만, 외래 키를 대상 테이블에서 관리하고 주 테이블의 락커 필드는 읽기 전용이 된다.

정리

  • 주 테이블에 외래 키

    • (주 테이블 : 많이 접근하는 테이블)

    • 주 객체(많이 사용하는 객체)가 대상 객체의 참조를 가지는 것 처럼

    • 주 테이블에 외래 키를 두고 대상 테이블을 찾는 방식.

    • 객체지향 개발자들이 선호하고, JPA 매핑이 편리하다.

    • 장점

      • 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인이 가능하다.

    • 단점

      • 값이 없으면 외래 키에 NULL을 허용해야 한다. DB입장에서는 치명적일 수 있다.

  • 대상 테이블에 외래키

    • 대상 테이블에 외래 키가 존재한다.

    • 전통적인 데이터베이스 개발자들이 선호하는 방식이다. NULL을 허용해야 하는 문제도 없다.

    • 장점

      • 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조를 유지할 수 있다.(멤버가 락커를 여러개 가지도록 비즈니스 룰이 변경될 경우 테이블 구조 유지하면서 유지보수 가능)

    • 단점

      • 코드상에서는 주로 멤버 엔티티에서 락커를 많이 엑세스 하는데, 어쩔 수 없이 양방향 매핑을 해야한다.

        • 일대일 - 대상 테이블에 외래 키 단방향 매핑을 JPA에서 지원하지 않으므로, 단방향 매핑만 해서는 멤버 객체를 업데이트 했을 때 락커 테이블에 FK를 업데이트 할 방법이 없다. 따라서 양방향 매핑을 해야 한다.

      • JPA가 제공하는 기본 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩 된다.(프록시는 뒤에서 학습)

        • JPA 입장에서 일대일 관계의 주 테이블에 외래 키를 저장하는 상황에서는, 멤버 객체를 로딩할 때, 멤버 테이블의 FK에 락커 ID가 있는지 없는지만 판단하면 된다. 있으면 프록시 객체를 넣어주고, 없으면 null을 넣으면 된다. 나중에 진짜 락커 필드에 엑세스 할 때, 그때 쿼리가 나간다.

        • 그런데, 대상 테이블에 외래 키를 저장한다면, JPA가 멤버의 락커를 조회하는 상황에서 DB의 멤버 테이블만 조회해서는 모른다. 어차피 락커 테이블을 찾아서 멤버가 있는지 확인 해야(쿼리를 날려 봐야) 알 수 있다. 어차피 쿼리가 나간단 이야기는 프록시를 만들 필요가 없다는 이야기이다. 그래서 하이버네이트 구현체 같은 경우는 지연 로딩으로 설정해도 항상 즉시 로딩 된다.


댓글