티스토리 뷰

Back-end/JPA

자바 ORM 표준 JPA 연관관계

이안_ian 2023. 5. 27. 00:11




반응형

단방향 연관관계

객체지향 모델링

출처에서 사용된 예시

하나의 팀이 여러 개의 멤버를 가질 때 보통 Member에서 team_id를 갖고 있는 설계를 많이 하게된다.

하지만 객체지향에서는 외래키 대신 객체 자체를 들고 있는 형태가 되어야 한다.

그래서 위와 같은 내용으로 Member쪽에 이렇게 설정을 해야한다.

@Entity
public class Member {
  중략..
  
  @ManyToOne(fetch = FetchType.LAZY) //Member, Team 관계를 나타내는 다:1(N:1)
  @JoinColumn(name = "TEAM_ID")
  private Team team;
}

이런식으로 단방향 매핑을 한 뒤에 member를 find 할 경우 매핑된 Team의 정보까지 같이 join되어 불러온다.

Member findMember = em.find(Member.class, 1L);
Team findTeam = findMember.getTeam();
String temaName = findMember.getTeam().getName();

만약에 현재 위에서 불러온 findMember의 team_id가 1일 경우 100인 team으로 바꾸고 싶을 경우 find로 객체를 불러와서 set만 해주게되면 DB에서는 team_id가 교체가된다.

Member findMember = em.find(Member.class, 1L);
Team newTeam = em.find(Team.class, 100L);

//DB에서는 Member 테이블에 있는 team_id가 1 -> 100으로 변경됨
findMember.setTeam(newTeam);

양방향 연관관계와 연관관계 주인

지금 상태에서는 Team에서 Member가 조회가 안된다.

근데 테이블 관계에서 둘은 외래키로 왔다갔다할 수 있다.

객체에서는 양방향으로 설정해줘야 하는데 Team에 List로 members를 넣어줘야한다.

이 부분이 객체와 테이블 연관관계의 가장 큰 차이점이다.

@Entity
public class Team {
  중략..
  
  @OneToMany(mappedBy = "team") //Member에서 사용하는 Team 객체 변수명
  private List<Member> members = new ArrayList<>(); //new ArrayList는 nullPoint도 막아주고, 관례적으로 사용
}

이렇게하면 이제 Team이 갖고 있는 멤버들이 조회가 된다.

Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();

for(Member m : members){
  sout("m = " + m.getUsername());
}

테이블의 양방향 관계는 외래 키 하나로 두 테이블의 연관관계를 관리한다.

select *

from member m

join team t on m.team_id = t.team_id

 

select *

from team t

join member m on m.team_id = t.team_id

 

그러나 객체의 양방향 관계는 사실 양방향이 아니라 서로 다른 단방향 관계 2개다. 그래서 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.

A -> B (a.getB())

B -> A (b.getA())

 

 

단방향일 때는 큰 문제가 없는데 양방향일 때는 둘다 참조가 되기 때문에 Member가 Team을 바꾸고 싶을 때 Member에서  외래키를 바꿔야할지? Team에서 외래키를 바꿔야할지? 고민을 하게된다.

그렇기때문에 둘 중 하나로 외래 키를 관리해야 한다.

연관관계의 주인(Owner)

양방향 매핑 규칙

  • 객체의 두 관계중 하나를 연관관계의 주인으로 지정
  • 연관관계의 주인만이 외래 키를 관리(등록, 수정)
  • 주인이 아닌쪽은 읽기만 가능
  • 주인은 mappedBy 속성 사용X
  • 주인이 아니면 mappedBy 속성으로 주인 지정

그래서 Team에 mappedBy가 지정된 members에서는 조회만 가능할 뿐 어떠한 수정이 되지않는다.

누구를 주인으로?

외래 키가 있는 곳을 주인으로 정해라.

그리고 DB관점에서 외래 키가 있는 곳이 N이다. 없는 곳이 1이고(N:1), @ManyToOne 설정하는 곳

여기서는 Member.team이 연관관계 주인이며 진짜 매핑이고, Team.members는 가짜 매핑(조회용)

 

아래와 같은 실수를 하지 말아야한다.

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Memeber member = new Member();
member.setName("member1");

team.getMembers().add(member);

//이럴경우 member에 team_id는 null이 된다. 연관관계 주인으로 값을 설정해야함
em.persist(member);

 

그리고 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자.

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Memeber member = new Member();
member.setName("member1");
member.setTeam(team);

em.persist(member);

//이때 위에서 추가된 memeber는 출력되지 않는다, 왜냐면 1차 캐시 데이터를 불러오기 때문에
//em.flush()나 em.clear()를 하고 find하기전까진 미노출이다.
Team findTeam = em.find(Team.class, team.getId());

//그렇기에 양쪽 다 데이터를 넣어주는게 좋다.
team.getMembers().add(member);

 

연관관계 편의 메소드를 생성하자.

@Entity
public class Member {
  중략..
  
  public void setTeam(Team team){  //chageTeam 같은 메소드로 변경하자 setter는 지양
    this.team = team;
    
    team.getMembers().add(this);
  }
}

 

양방향 매핑시에 무한 루프를 조심하자.

예) toString(), lombok, JSON 생성 라이브러리

@Entity
pulbic class Member {
  중략..
  
  @ManyToOne
  @JoinColumn(name = "team_id")
  private Team team;
  
  @Override
  public String toString(){
    //간소화 리턴 값
    return "team=" + team;
  }
}

@Entity
pulbic class Team {
  중략..
  
  @OneToMany(mappedBy = "team")
  private List<Member> members = new ArrayList<>();
  
  @Override
  public String toString(){
    //간소화 리턴 값
    return "members=" + members;
  }
}

이런식으로 서로가 서로를 계속 호출하게되어 무한루프에 빠져 StackOverflowError가 발생한다.

 

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

 

 

반응형

'Back-end > JPA' 카테고리의 다른 글

자바 ORM 표준 JPA fetch join  (0) 2023.05.29
JPA @MappedSuperclass  (0) 2023.05.28
자바 ORM 표준 JPA DDL, 기본키 매핑  (0) 2023.05.25
자바 ORM 표준 JPA 플러시, 준영속  (0) 2023.05.24
자바 ORM 표준 JPA 영속성 컨텍스트  (0) 2023.05.23
댓글
반응형
최근에 달린 댓글
글 보관함
Total
Today
Yesterday
최근에 올라온 글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30