Spring

[스프링부트] - JPA 연관관계

코린이 파닥거리기 2025. 4. 30. 01:36
728x90
반응형
SMALL

JPA에서 연관관계는 

객체간의 관계를 표현하고 DB테이블 간의 관계를 연결하는 역할을 한다.

 

두가지의 접근방향이 있는데

  • 단방향(One-way)
  • 양방향(Bidirectional)

연관관계로 표현할 수 있는 종류는 4가지다.

  • 다대일(N:1)
  • 일대다(1:N)
  • 일대일(1:1)
  • 다대다(N:N)
@Entity
@Data
public class Team {
     @Id
     int teamId;
     String teamName;
}
@Entity
@Data
public class Player {
    @Id
    int playerId;
    String playerName;
}

여기 Team 엔티티와 Player 엔티티가 있다.

 

@ManyToOne(N:1) 단방향

자 여기서 우리는 DB의 N:1을 생각하면 쉽다.

※한개의 Team이 여러명의 Player를 가진다.

라고 생각하면 된다.

그래서 Player객체에 

    @ManyToOne
    @JoinColumn(name="team_id")
    Team teams;

해당 코드를 엔티티 메서드 본문 아래에 추가해주면 된다.

JoinColumn은 DB칼럼명을 명시해주는거다.

--> 보통 필드명 + _ + 참조하는 테이블의 칼럼명으로 지어준다.

 

그럼 생성됐나 봐야된다.

이렇게 team_id로 생성된 것을 볼 수 있다.

 

양방향과 단방향

OneToMany기준

단방향(unidirectional)은 상대 엔티티에 @ManyToOne이 없는 경우,
양방향(bidirectional)은 상대 엔티티에 @ManyToOne이 있는 경우

 

@ManyToOne기준

단방향(unidirectional)은 상대 엔티티에 @OneToMany가 없는 경우,
양방향(bidirectional)은 상대 엔티티에 @OneToMany가 있는 경우

 

두 개의 기준에는 명시만다를 뿐 다를게 없다.

일단 OneToMany어노테이션을 가지고 있는 객체가 부모 엔티티가 되기 때문이다.

즉, FK를 들고 있는 객체가 자식 엔티티가 된다.

 

연관관계 주인(mappedBy)

연관관계는 주인이라는 개념을 가지고 있다.(이번에 정리하면서 새로 알았다...)

주인은 연관관계의 관리주체이고, 연관관계를 관리할 책임을 가지고 있다.

※주인 엔티티와 부모 엔티티는 다르다.

왜?

  • 부모, 자식은 의존도를 통해서 정해진다.
  • 주인 엔티티는 DB에 저장되는 FK를 어떤 엔티티가 삽입,수정,삭제를 담당할 지를 정하는 과정에서 자연스럽게 정해진다.

단방향의 경우, 주인은 자연스럽게 mappedBy어노테이션이 존재하는 엔티티가 된다.

당연히 해당 어노테이션을 들고 있는 엔티티가 관리해야 된다라는 쪽으로 그냥 받아드려라

but!!>!!!

FK를 들고있는 'Many' 쪽의 자식 엔티티가 주인이 되는 것이 더 자연스럽다.

그 이유는 JPA는 객체모델과 DB모델을 매핑하기 때문에 어느 한쪽이 DB에 있는 키 칼럼의 값을 변경하고 실제로 반영해야한다.

※외래키 FK가 있는 곳을 연관관계의 주인으로 정하면된다. 무조건.(JPA에서 정한 규칙같은거라고 보면 됨)

 

@OneToMany(1:N) 단방향

상대 엔티티를 참조할 수 있는 매핑이 부모 엔티티쪽에 존재 

but, FK는 자식 엔티티 테이블에 존재하는 연관관계이다.

 

OneToMany단방향만 사용할 경우 FK를 만드는 것보다 비효율적이며

자식 엔티티를 제거할 때 성능문제로 이어진다.

※OneToMany단방향은 잘 사용 안한다고 하네

 

@ManyToOne(OneToMany) 양방향

DB관점에서 단방향 @ManyToOne과 차이점이 없고, 상대 엔티티에서 참조할 수 있는 변수가 생기는 장점이 있다.

public class Player {
    @Id
    int playerId;
    String playerName;
    @ManyToOne
    @JoinColumn(name="team_id")
    Team team;
}

 

public class Team {
    @Id
    int teamId;
    String teamName;
    @OneToMany(mappedBy = "team")
    List<Player> players = new ArrayList<>();
}

team은 다수의 Player를 가질 수 있기 때문에 List<Player>형으로 객체를 정의한다.

하나의 team이 여러개의 player를 가질 수 있으므로 @OneToMany어노테이션을 추가한다.

player엔티티의 player정보를 참고할 것이기때문에 mappedBy를 통해 연관관계 team을 매핑한다.

(생갹하고 실행시 중간테이블이 생성된다!)

※player에 선언되어있는 Team객체의 이름은 "team"이기 때문이다.

 

 

@OneToMany쪽에 mappedBy를 설정해서 상대 엔티티에서 어떻게 매핑되는지 설명하고

@ManyToOne쪽에서 @JoinColumn을 통해 Fk칼럼명을 명시적으로 정의한다.

 

이렇게 엔티티를 구성하고

자 이제 테스트코드로 테스트를 해보입시다잉

   @Test
   @Transactional
   void playerToTeam() {
      List<Player> players = playerRepository.findAll();
      for (Player player : players) {
         System.out.printf(
               "%s : %s\n", player.getPlayerName(),
               player.getTeams().getTeamName());
      }
   }

Player테이블
Team테이블

자 여기서 Player를 조회하는 코드이므로 

회원1: A팀 뭐 이런식으로 나와야한다.

Players를 매핑을 잘 해서 출력이 잘 되는 것을 알 수 있다.

 

 

 

 

많이 배웠습니다...센세...

https://velog.io/@goniieee/JPA-OneToMany-ManyToOne%EC%9C%BC%EB%A1%9C-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0

 

JPA @OneToMany, @ManyToOne으로 연관관계 관리하기

안녕하세요, 오늘은 스프링을 이용하면서 자주 쓰는 JPA에 대해서 이야기해보려고 합니다. JPA는 스프링 개발을 하면서 이제 거의 필수가 된 ORM 기술입니다. @OneToMany, @ManyToOne 어노테이션은 1:N, N:1

velog.io

 

다음 포스팅은 lazy관련 포스팅입니다.ㅎㅎ

728x90
반응형
LIST