본문 바로가기
JPA/JPA 기초

JPA 정리(3) - 연관관계, 양방향 매핑

by 옹알이옹 2023. 7. 17.

 

Entity의 연관 관계

DB 테이블의 연관 관계와 비슷하지만 Entity의 연관 관계와 동일하지 않다.

 

여러가지 연관 관계

이미지 없음

  • 연관 관계를 가지고 있을 때 select 외의 insert등도 한번에 처리가 가능하다.
  • 가장 빈번하게 쓰이고 일반적인 형태, fk를 가지고 있는 Member테이블의 객체가 Team의 참조를 가지고 있다

이미지 없음

  • 실무에서 거의 사용되지 않는 형태지만 지원되긴 한다.
  • 테이블에서는 무조건 다쪽에 fk가 들어간다.
  • 로직에서 조회의 빈도성 때문에 일대다를 사용해야 한다면 차라리 다대일 양방향 매핑을 사용

이미지 없음

  • 이런 매핑은 공식적으로 존재하지 않는다.
  • @JoinColumn(insertable=false, updatable=false) 사용
  • 읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법
  • 다대일 양방향을 사용하자

다대일(N:1) 양방향

이미지 없음

양방향 매핑 규칙

  • 객체의 두 관계 중 하나를 관계의 주인으로 지정해야 함
  • 관계의 주인만이 외래키를 관리(등록,수정)
  • 주인이 아닌쪽은 읽기만 가능
  • 주인은 mappedBy 속성을 사용하지 않는다
  • 주인이 아니면 mappedBy 속성으로 비주인 지정
  • 외래키가 있는 곳을 주인으로 정해라!!
양방향 매핑은 DB 테이블에는 없는 관계입니다. 왜냐하면 table에서는 fk를 통해 자식 테이블이 부모 테이블의 
참조 값을 가지고 그것으로 모든 것을 하기 때문입니다.
하지만 Entity 관계에서는 부모 자식 모두 서로를 참조할 수 있고 개념이 어렵다고 생각합니다.

 

양방향 매핑 예시 코드

관계의 주인쪽에만 매핑을 해주어도 원하는 결과가 도출 (insert시 fk값도 들어감) 되는데 왜 양쪽 모두 매핑을 해주어야 하는가?

case1 : 양방향 관계지만 서로의 참조값을 주인 객체에만 매핑한 경우

public static void main(String[] args){
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaInf");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            // 1. 팀 객체 생성
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);

            // 2. 멤버 객체 생성 및 팀 객체 매핑
            Member member = new Member();
            member.setUserName("memberA");
            member.setTeam(team);
            em.persist(member);

            // 3. 팀 객체 조회 => 팀은 1번에서 영속성 컨텍스트에 올라감(1차 캐시에 존재, Member객체 매핑 X)
            Team findTeam = em.find(Team.class, team.getId());
            // 4. 팀 객체에서 매핑 되어 있는 회원들 조회 => Memeber객체가 매핑 되어 있지 않아 조회 되지 않음
            List<Member> memberList = findTeam.getMemberList();

            System.out.println("=============================================");
            for(Member m : memberList){
                System.out.println("m2 = "+ m.getUserName());
            }
            System.out.println("=============================================");

            tx.commit();

        }catch (Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }

결과

- DB에는 member의 teamId값도 잘 들어가겠지만, commit() 전에 Team에서 Member를 조회 하는 행위는 실패한다.

이미지 없음

 

 

 

case2 : 양방향 관계면서 양쪽 모두 매핑을 해준 경우

public static void main(String[] args){
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaInf");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try{
            // 1. 팀 객체 생성
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);

            // 2. 멤버 객체 생성 및 팀 객체 매핑
            Member member = new Member();
            member.setUserName("memberA");
            member.setTeam(team);
            em.persist(member);

            // ✔ 팀 객체에도 멤버 객체 매핑
            team.getMemberList().add(member);

            // 3. 팀 객체 조회 => 팀은 1번에서 영속성 컨텍스트에 올라감(1차 캐시에 존재)
            Team findTeam = em.find(Team.class, team.getId());
            // 4. 팀 객체에서 매핑 되어 있는 회원들 조회
            List<Member> memberList = findTeam.getMemberList();

            System.out.println("=============================================");
            for(Member m : memberList){
                System.out.println("m2 = "+ m.getUserName());
            }
            System.out.println("=============================================");

            tx.commit();

        }catch (Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }

결과

- Team객체에도 Member객체를 매핑 해주었기 때문에 Team에서 Member 조회 가능

이미지 없음

양방향 매핑 정리

  • 단방향 매핑만으로 이미 연관관계 매핑 완료
  • 앵간하면 단방향 매핑에서 끝내도록 하자
  • 양방향 매핑은 반대 방향으로 조회 기능이 추가된 것 뿐
  • JPQL에서 역방향으로 탐색할 일이 많음
  • 단방향 매핑을잘 하고 양방향은 필요할 때 추가해도 됨 ⇒ 테이블은 영향을 받지 않는다.
  • 연관 관계의 주인은 외래 키가 존재하는 테이블의 Entity로 정해야함

 

* 해당 글은 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 강의를 참조하여 작성하였습니다.

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

반응형