ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 연관관계1
    Spring 2025. 4. 16. 16:22

    minecraft-font

    #단방향 #양방향

    💡 Spring 정리: 연관 관계 1

    📘 개념 정리

    🔥연관관계

     

          🎯 JPA를 통해 데이터베이스 테이블 간의 관계를 객체 지향적으로 표현하여 엔티티 클래스들 간의
               관계를 설정 하여,  연관관계를 매핑하면 SQL을 직접 작성하지 않고도 객체 간의 관계를 활용하여
                쉽게 데이터를 조회하고 조작할 수 있다.

     

           🎯  Entity(Table)들간의 연관 관계가 존재하는 경우
                  1.  명시적으로 표현하고 관리함
                   2. 데이터 조회의 효율성과 유지보수의 편의성을 높이는 것 주요 목적이다.        

     

       단방향 ❓ , 양방향❓

    방향 단방향  양방향 
    정의 하나의 Entity만  다른 Entity를 참조하는 관계 양쪽 Entity가 서로를 참조하는 관계
    테이블 외래키(FK) 하나로 모든 테이블 JOIN이 가능하다.
    객체 외래키가 있는 객체만 참조가 가능하다. 참조용 필드가 양쪽에 있는 경우일때 가능하다.
    설명

      ●  A (기준) → B
       (A에서는 B를 조회가 가능하지만,  
         B에서 A를 조회가 불가능) 


      ●
      연관 관계의소유자(Owner)가
         한쪽만 존재

                     
    ● A ↔ B
       (A는 B를, B는 A를 조회할 수 있음)


       소유자(Owner) 와 비소유자(반대편) 를 구분해야 함

     ●  보통 JPA에서 연관관계 주인 설정이 중요
     이용 조회/저장의 필요에 따라 사용됨
    장점 구조가 단순해 실수를 줄일수 있다.

    관리해야 할 연관관계가 적어 
    유지보수가 쉽다.
     객체 그래프 탐색이 자유로움 
    → Member.getOrders()
         식으로 바로 접근 가능


    화면에 필요한 데이터를 효율적으로
    조회하기 좋음

    단점 반대쪽에서 관계를 타고 조회하거나
    조작할 수 없음

    → 결국 JPQL, 서브쿼리 등 다른 방식 필요할 수 있음
    연관관계의 주인 개념을 정확히 이해하고
    설정해야 함
    → mappedBy, @JoinColumn 실수하면
        무한 루프/데이터 이상 발생 가능


    관리 난이도가 높다.
     (특히 양방향 양쪽에 set 메서드 안 맞추면...)

     

    ※ 단방향 예시.

    class Member {
        @ManyToOne
        @JoinColumn(name = "team_id")
        private Team team; // Member는 Team을 안다 (Team은 Member를 모름)
    }

     

    • 외래키는 member.team_id
    • Team은 Member에 대해 아무것도 모름.

      양뱡향 예시

    class Member {
        @ManyToOne
        @JoinColumn(name = "team_id") // ✅ 주인
        private Team team;
    }
    
    class Team {
        @OneToMany(mappedBy = "team") // ❌ 비주인 (거울)
        private List<Member> members;
    }

     

    • 외래 키는 여전히 Member 테이블에 존재

    ⚠️ 실수 및 주의사항

     

     

    현실 세계에서 사람이 팀에 "소속된다" → 그러면 Member가 주인인가?
     
       소속되는 쪽이 연관관계의 주인이다.
       (-> 외래 키를 가짐 = @JoinCloumn 붙은쪽) 

     주인은 외래 키 보유자라며, 그럼 Member가 기준이 되는 건가?

          양방향이라고 해도 주인은 한쪽이다.

     

     단방향과 양방향을 쪼개서 실질적으로 어떻게 구분하면 좋을까?

     현실 모델링과 연관관계 매핑은 대체로 일치하지만,

     

           항상, '외래키가 어느 테이블에 있어야 자연스러운가?'로 판단한다.

     

     양방향일때 둘다 주인인 줄 안다.

    //문제
    //@OneToMany
    //@JoinColumn(name = "team_id")
    //private List<Member> members;
    
    @OneToMany(mappedBy = "team")
    private List<Member> members;

     

    • ❌ 양쪽에 @JoinColumn 붙이는 실수
    • ❗ 그러면 JPA가 외래 키를 두 번 만들려 해서 에러 또는 이상한 테이블 생성 발생

    •  

     비주인(mappedBy)쪽만 수정하면 DB 반영될 줄 안다.

    //class Team
    //team.getMembers().add(member); // ❌ 아무 일도 일어나지 않음
    members.add(member);
    member.updateTeam(this); // 주인 쪽에서 외래 키 업데이트
        
     
    //class Member
    member.updateTeam(team);
    public updateTeam(Team team){
       this.team =team;
    }
    • 반대편에만 넣으면 실제로 외래 키 업데이트가 안 됨

    • 주인 쪽을 통해 연관관계를 설정해야 JPA가 변경사항 감지함
    •  Team에서 업데이트 

    if(!team.getMembers().contains(this))는 정말 필요할까?

     대부분의 경우 contains 체크는 생략이 가능하다. 중복 추가가 실제 문제일 때만 사용하는 것이 옳다.

    ✅ 왜 생략해도 되는가?

    1. 연관관계 메서드는 보통 한 번만 호출됨

    • addMember()updateTeam() 같은 메서드는 보통 특정 시점에 한 번만 호출된다.
    • 중복 추가될 구조 자체가 적다.

    2. JPA는 동일 엔티티는 하나만 관리함

    • JPA는 영속성 컨텍스트에서 같은 식별자의 엔티티는 하나로 취급한다.
    • 따라서 중복 add()하더라도 DB에는 영향을 주지 않는다.

    3. contains()는 성능 비용이 있다

    • 내부적으로 equals()를 이용한 순회가 발생한다.
    • 멤버 수가 많을수록 성능 저하 가능성이 있음

    4. 실제로 방어가 필요하다면 Set을 쓰는 것이 구조적으로 낫다

    • 컬렉션 자체를 Set으로 바꾸면 중복 자동 방지 가능

    ❗ 하지만 예외 상황은 존재한다

    • 사용자가 임의로 연관관계를 반복적으로 추가할 수 있는 구조
    • 외부 입력 또는 동시성 환경에서 중복 요청이 올 수 있는 경우

    이럴 땐 contains()를 써서 명시적 방어를 해주는 게 맞다.


     

    public void addMember(Member member) {
        members.add(member);             // 중복 검사 생략
        member.updateTeam(this);        // 주인 쪽 연관관계 설정
    }
    • 간결하고 명확하며, 중복 자체는 도메인 혹은 구조로 방지한다.

    🧠 최종 정리

    기준판단

    중복이 비즈니스 오류인가? ✅ contains 고려
    연관관계 메서드가 1회성인가? ❌ 생략 가능
    성능에 민감하거나 멤버 수가 많나? ❌ 생략 권장
    컬렉션을 Set으로 바꿀 수 있나? ✅ 구조로 해결

    🔥 중복 방지는 코드가 아니라 구조와 책임 분리로 해결하는 것이 실무다.

     

     

     

     

    'Spring' 카테고리의 다른 글

    [Spring] Proxy  (0) 2025.04.16
    [Spring] 연관관계 유형  (0) 2025.04.16
    [Spring] API 예외 처리 @ExceptionHandler  (0) 2025.04.15
    [Spring] Bean Scope  (0) 2025.04.15
    [Spring] @PostConstruct, @PreDestroy  (0) 2025.04.15
Designed by Tistory.