CS/자바 ORM 표준 JPA 프로그래밍

[JPA] 연관관계 매핑

jisu0708 2024. 1. 7. 17:32
해당 포스트는 김영한 님의 [자바 ORM 표준 JPA 프로그래밍] 을 읽고 정리한 글입니다.

 

1. 단방향 연관관계

 

@Entity
public class Member {
	
	@Id @GeneratedValue
	private Long id;

	@Column(name = "USERNAME")
  private String name;
  private int age;

//@Column(name = "TEAM_ID")
//private Long teamId;

	@ManyToOne
	@JoinColumn(name = "TEAM_ID")
	private Team team;
 ...

 

→ 현재 상황에서 Team에서 member 접근은 불가

 

 

2. 양방향 매핑

 

테이블의 연관관계는 바뀌지 않은 채 양방향 객체 연관관계를 만든다.

 

@Entity
public class Member {
	
	@Id @GeneratedValue
	private Long id;

	@Column(name = "USERNAME")
  private String name;
  private int age;

	@ManyToOne
	@JoinColumn(name = "TEAM_ID")
	private Team team;
 ...

 

@Entity
public class Team {

	@Id @GeneratedValue
	private Long id;
	
	private String name;
	
	@OneToMany(mappedBy = "team")
	List<Member> members = new ArrayList<Member>()
	...
}
  • Team 엔티티에 컬렉션을 추가

 

 

양방향 매핑 (반대 방향으로 객체 그래프 탐색)

//조회
Team findTeam = em.find(Team.class, team.getId());

int memberSize = findTeam.getMembers().size(); //역방향 조회

 

 

3. 연관관계의 주인과 mappedBy

1) 객체와 테이블이 관계를 맺는 차이

객체 연관관계 = 2개

  • 회원 -> 팀 연관관계 1개(단방향)
  • 팀 -> 회원 연관관계 1개(단방향)

테이블 연관관계 = 1개

  • 회원 <-> 팀의 연관관계 1개(양방향)

→ 객체의 양방향 관계는 서로 다른 단방향 관계 2개다.

→ 테이블은 외래 키 하나(MEMBER.TEAM_ID)로 두 테이블의 연관관계를 관리한다.

 

2) 연관관계의 주인 (Owner)

양방향 매핑 규칙

  • 연관관계의 주인만이 외래 키를 관리 (등록, 수정) → 외래 키가 있는 곳이 주인
  • 주인이 아닌 쪽은 읽기만 가능
  • 주인이 아니면 mappedBy 속성으로 주인 지정

 

→ 양방향 매핑시 연관관계의 주인에 값을 입력해야 한다. (member.setTeam(team);)

→ 순수한 객체 관계를 고려하면 항상 양쪽 다 값을 입력해야 한다.

 

단방향 매핑만으로도 이미 연관관계는 매핑 완료되었다. 양방향 매핑은 반대 방향으로 조회가 가능하게 한다.

 

 

4. 다대일 (N:1)

1) 다대일 단방향

  • 가장 많이 사용하는 연관관계
  • 다대일의 반대는 일대다

 

2) 다대일 양방향

  • 외래 키가 있는 쪽이 연관관계의 주인
  • 양쪽을 서로 참조하도록 개발

 

 

 

5. 일대다 (1:N) → 권장 X

  • 일대다 단방향은 일대다(1:N)에서 일(1)이 연관관계의 주인
  • 테이블 일대다 관계는 항상 다(N) 쪽에 외래 키가 있음
  • 객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
  • @JoinColumn을 꼭 사용해야 함. 그렇지 않으면 조인 테이블 방식을 사용함(중간에 테이블을 하나 추가함)

→ 하지만 일대다 단방향 매핑의 경우, 외래 키가 다른 테이블에 있어 연관관계 관리를 위해 추가로 UPDATE SQL을 실행해야 한다.

→ 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자!

(일대다 양방향 매핑은 공식적으로 존재 X)

 

 

6. 일대일 (1:1)

1) 주 테이블에 외래 키 단방향

  • 외래 키에 데이터베이스 유니크 제약조건 추가

 

2) 주 테이블에 외래 키 양방향

  • 외래 키가 있는 곳이 연관관계의 주인
  • 반대편은 mappedBy 적용

대상 테이블에 외래 키 단방향 관계는 JPA가 지원하지 않는다. 양방향 관계는 지원하는데 이게 결국 주 테이블에 외래 키 양방향…

 

3) 정리

주 테이블에 외래 키

  • 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
  • 객체지향 개발자 선호
  • JPA 매핑 편리
  • 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
  • 단점: 값이 없으면 외래 키에 null 허용

대상 테이블에 외래 키

  • 대상 테이블에 외래 키가 존재
  • 전통적인 데이터베이스 개발자 선호
  • 장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
  • 단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨(프록시는 뒤에서 설명)

 

 

7. 다대일 (N:M)

관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없어 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 한다.