인프런 - 자바 ORM 표준 JPA 프로그래밍 (김영한님)
1. 단방향 연관관계
객체의 참조와 테이블의 외래키를 매핑
- Member(1)와 Team(M)은 일대다 관계
- 테이블 연관관계
- 테이블은 외래키로 조인을 사용해 연관된 테이블을 탐색
- 객체 연관관계
- 객체는 참조를 사용해서 연관된 객체를 탐색
@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;
}
Team team = new Team();
team.setName("TeamA");
em.persist(team);
// Member 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
- @ManyToOne(fetch=FetchType.LAZY)
- 지연 로딩 전략
2. 양방향 연관관계와 연관관계의 주인
* Member에서 Team 조회 시
member.getTeam();
* Team에서 Member 조회 시
- DB에서는 조회가 가능하지만, 단방향 연관 관계에서는 조회 불가능
- Team.getMember()? 를 할 수 없으니까
- DB에서 양방향 조회
- 외래키 하나로 양쪽에서 조회 가능
- Member에서 Team FK로 join해 Team을 알 수 있음
- Team에서 Team FK로 join해 Member를 알 수 있음
- 객체
- 양방향 매핑이 필요
양방향 매핑 설정
객체는 가급적 단방향 연관관계가 좋음
// Member는 단방향과 동일
@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에서 Member 조회
Team findTeam = em.find(Team.class, team.getId());
List<Member> members = findTeam.getMembers();
객체와 테이블의 연관관계 차이
- 객체의 연관관계 = 2개
- Member -> Team (단방향)
- Team -> Member (단방향)
- 객체를 양방향으로 참조하려면 둘 중 하나에서 외래키를 관리해야 함
- 테이블 연관관계 = 1개
- Member <-> Team (양방향, 방향이 없음)
연관관계의 주인(Owner)
- 양방향 매핑 규칙
- 객체의 두 관계 중 하나를 연관관계의 주인으로 지정
- 연관관계의 주인만 외래키를 관리 (등록, 수정)
- 주인이 아닌 쪽은 읽기만 가능
- mappedBy 속성으로 주인 지정
- 연관관계의 주인은 어느쪽?
- 외래키가 있는 곳을 주인으로!
- DB에서도 외래키가 있는 곳이 M, 없는 곳이 1
- Member.team이 연관관계 주인 (@~ToOne)
- 비즈니스적으로 중요해서 주인이 아니라 DB에 의해 결정, 즉 외래키가 있는 곳이 주인
- 외래키가 있는 곳을 주인으로!
양방향 연관관계와 연관관계의 주인 주의점
- 연관관계의 주인에 값을 입력하지 않음
- mappedBy는 읽기 전용으로 JPA에서 insert, update시에 mappedBy 변수는 체크하지 않음
- 아래 코드처럼 Member에는 Team을 저장하지 않고, Team에만 Member를 저장할 시 team.getMembers()는 읽기 전용이므로 DB에 저장되지 않아 Member테이블의 TEAM_ID에는 null로 저장됨
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
// 역방향만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
- 순수한 객체 관계를 고려하면 항상 양쪽 다 값을 입력해야 한다
- team.getMembers().add(member)는 DB에 저장되지 않으므로 작성안해줘도 됨
- 하지만 작성하지 않으면 1차 캐시에는 team.getMember()가 비어 있음
- 즉, 양방향 연관관계면 양쪽에 값을 세팅하는 게 좋음
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member);
// 연관관계 주인에 값 설정 (필수)
members.setTeam(team);
em.persist(member);
- 연관관계 편의 메소드 생성
public void setTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
양방향 매핑 정리
- 단방향 매핑만으로도 이미 연관 관계 매핑은 완료
- 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
- JPQL에서 역방향으로 탐색할 일이 많음
'STUDY > JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 프록시와 연관관계 관리 (0) | 2023.12.10 |
---|---|
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 고급 매핑 (0) | 2023.12.10 |
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 다양한 연관관계 매핑 (1) | 2023.12.10 |
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 엔티티 매핑 (1) | 2023.12.10 |
[자바 ORM 표준 JPA 프로그래밍 - 기본편] 영속성 관리 (0) | 2023.12.10 |