단방향
단방향 연관관계는 객체 간의 관계가 한쪽에서만 참조될 수 있는 관계를 말함. 설정이 단순하고 유지 관리가 쉬우며 불필요한 데이터 접근을 방지할 수 있다.
1. DB 중심

- FK 값은 Tutor가 가지고 있다.
- Tutor만 참조할 수 있다.
- N:1, 다대일 연관관계에 가장 많이 사용된다.
- 여러명(N)의 Tutor가 어떤 Company(1)에 소속 되어있는지 설정할 수 있다.
- 코드
@Entity
@Table(name = "company")
public class Company {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// 기본 생성자, getter/setter
}
// Company 생성 및 persist
Company company = new Company("toss");
em.persist(company);
// Tutor 생성, setCompanyId, persist
Tutor tutor = new Tutor("PBC");
tutor.setCompanyId(company.getId());
em.persist(tutor);
// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());
// 조회한 Tutor의 CompanyId로 Company 조회
Long companyId = findTutor.getCompanyId();
Company findCompany = em.find(Company.class, companyId);
- 객체 지향적인 코드를 작성할 수 없다.
- Java Collection을 사용하는 것처럼 tutor.getCompany()를 사용하지 못한다.
2. 객체 지향

- 객체는 다른 객체를 참조한다.
- N : 1 관계는 @ManyToOne, @JoinColumn을 사용한다.
- 코드
@Entity
@Table(name = "tutor")
public class Tutor {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// N:1 단방향 연관관계 설정
@ManyToOne
@JoinColumn(name = "company_id")
private Company company;
// 기본 생성자, getter/setter
}
// Company 생성 및 persist
Company company = new Company("sparta");
em.persist(company);
// Tutor 생성, setCompany, persist
Tutor tutor = new Tutor("wonuk");
tutor.setCompany(company);
em.persist(tutor);
// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());
// 조회한 Tutor의 Company 조회
Company findCompany = findTutor.getCompany();
- Tutor의 FK와 Company의 PK를 @JoinColumn 으로 매핑한다.
- JavaCollection을 사용하는 것처럼 tutor.getCompany() 를 사용할 수 있다.
양방향 연관관계
양방향 연관관계는 객체 간의 관계가 양쪽에서 서로를 참조할 수 있는 관계를 의미한다. 이를 통해 양쪽에서 데이터를 쉽게 접근할 수 있지만 관계를 관리할 때 한쪽에서만 연관관계를 설정하거나 삭제하지 않도록 주의가 필요하다.
테이블

- 테이블에 변화는 없다.
- Tutor 테이블의 FK로 Company 테이블에 JOIN
- Company 테이블의 PK로 Tutor 테이블에 JOIN
- 사실상 테이블의 연관관계에는 방향의 개념이 없다.
객체

- 코드
@Entity
@Table(name = "tutor")
public class Tutor {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// N:1 단방향 연관관계 설정
@ManyToOne
@JoinColumn(name = "company_id")
private Company company;
// 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// null을 방지하기 위해 ArrayList로 초기화 한다.(관례)
@OneToMany(mappedBy = "company")
private List<Tutor> tutors = new ArrayList<>();
// 기본 생성자, getter/setter
}
- 양방향 연관관계 설정을 위해 mappedBy 속성을 설정한다.
- Tutor의 company 필드와 매핑된다.
// Company 생성 및 persist
Company company = new Company("sparta");
em.persist(company);
// Tutor 생성, setCompany, persist
Tutor tutor = new Tutor("wonuk");
tutor.setCompany(company);
em.persist(tutor);
// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());
// 조회한 Tutor의 Company 조회
Company findCompany = findTutor.getCompany();
// Company에 속한 Tutor List 조회
List<Tutor> tutors = findCompany.getTutors();
양방향 연관관계의 주인
mappedBy는 JPA 양방향 연관관계 설정 시 사용되는 속성으로 두 엔티티 간의 관계에서 연관관계의 주인이 아닌 쪽에 선언한다.
이를 통해 외래 키 관리 책임을 주인 엔티티에 두고 매핑이 중복되지 않도록 한다.

- Tutor의 Company를 수정할 때 FK가 수정
- Company의 Tutor를 수정할 때 FK가 수정
- Tutor가 새로운 Company를 간다면?
- Tutor의 참조값 Company 수정
- Company의 참조값 List tutors 수정
- DB입장에서는 FK만 수정되면 된다.
- 결국, 둘 중 하나로만 외래 키를 관리해야 한다.
- Tutor가 새로운 Company를 간다면?
- 양방향 연관관계 규칙

- 두개의 Entity 중 하나를 연관관계의 주인으로 설정 해야한다.
- 연관관계의 주인은 mappedBy 속성을 사용하지 않는다.
- 연관관계의 주인이 아니라면 mappedBy 속성을 사용한다.
- 연관관계의 주인이 아니라면 조회만 가능하다.
- 연관관계의 주인만 외래 키를 관리(등록, 수정)할 수 있다.
- 연관관계의 주인 선정 기준
- 항상 FK가 있는 곳을 연관관계의 주인으로 지정한다.
- 양방향 1 대 N 관계에서 주인을 N 쪽에 두는 것이 일반적이다. 이유는 N 쪽에 외래키가 존재하기 때문에 N 쪽에서 외래키를 관리하는 것이 자연스럽다.
실무에서의 사용 전략
- 단방향 연관관계:
- 권장: 대부분의 경우 단방향을 기본으로 설계.
- 이유: 간단하고 성능상 유리.
- 양방향 연관관계:
- 필요할 때만 사용.
- 예: 부모-자식 관계에서 자식 데이터를 자주 조회해야 하는 경우.
연관관계 매핑 실무 팁
1. 연관관계 주인 설정
- 연관관계 주인은 외래 키를 관리하는 엔티티로 설정.
- 양방향일 때 주인만 수정해야 JPA가 외래 키를 제대로 관리.
2. 지연로딩 기본 설정
- 연관관계 필드에는 기본적으로 Lazy Loading을 설정해 불필요한 데이터 로딩 방지.
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
3. 데이터 설계 우선
- 객체 연관관계가 복잡할수록 데이터베이스 설계를 먼저 고민
- 일단 단방향 매핑만으로 이미 연관관계 매핑은 완료 되므로 단방향 매핑을 잘 하고 양방향은 필요할 때 추가하는 쪽으로
4. 필요하지 않으면 양방향을 피하자
- 양방향은 설계와 유지보수의 복잡성을 증가시키므로 꼭 필요한 경우에만 사용.
'Back-End > JPA' 카테고리의 다른 글
| JPA 연관관계 Mapping(2) (0) | 2024.12.14 |
|---|---|
| JPA 데이터베이스 스키마 자동 생성과 주의점 (1) | 2024.12.13 |
| JPA - Entity 만들기 (0) | 2024.12.10 |
| JPA의 지연 저장소, 변경 감지, 그리고 flush와 Commit (1) | 2024.12.10 |
| JPA - 영속성 컨텍스트(1차 캐시, 동일성 보장, 쓰기 지연) (0) | 2024.12.10 |