Home > Spring > πŸƒ[Spring] 연관관계 μ‚¬μš©μ‹œ κ³ λ €ν•΄μ•Ό ν•  사항듀은 무엇이 μžˆμ„κΉŒμš”?

πŸƒ[Spring] 연관관계 μ‚¬μš©μ‹œ κ³ λ €ν•΄μ•Ό ν•  사항듀은 무엇이 μžˆμ„κΉŒμš”?
Spring Framework

πŸƒ[Spring] 연관관계 μ‚¬μš©μ‹œ κ³ λ €ν•΄μ•Ό ν•  사항듀은 무엇이 μžˆμ„κΉŒμš”?

  • JPAμ—μ„œ 연관관계λ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” μ—¬λŸ¬ 가지 츑면을 κ³ λ €ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • 연관관계λ₯Ό 적절히 μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ μ„±λŠ₯ μ €ν•˜, λ³΅μž‘ν•œ νŠΈλžœμž­μ…˜ 관리, μœ μ§€λ³΄μˆ˜μ„± μ €ν•˜ λ“±μ˜ 문제λ₯Ό μ΄ˆλž˜ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

1️⃣ 연관관계 μ‚¬μš©μ‹œ κ³ λ €ν•΄μ•Ό ν•  ν•­λͺ©λ“€.

1️⃣ μ—°κ΄€κ΄€κ³„μ˜ λ°©ν–₯(단방ν–₯ vs μ–‘λ°©ν–₯)

1️⃣ 단방ν–₯ 연관관계.

  • ν•œμͺ½ μ—”ν‹°ν‹°λ§Œ λ‹€λ₯Έ μ—”ν‹°ν‹°λ₯Ό μ°Έμ‘°ν•˜λŠ” κ΄€κ³„μž…λ‹ˆλ‹€.
  • 단방ν–₯ μ—°κ΄€κ΄€κ³„λŠ” 섀계와 관리가 κ°„λ‹¨ν•˜κ³  μ„±λŠ₯ μ΅œμ ν™”μ—λ„ μœ λ¦¬ν•©λ‹ˆλ‹€.

2️⃣ μ–‘λ°©ν–₯ 연관관계.

  • μ„œλ‘œ μ°Έμ‘°ν•˜λŠ” κ΄€κ³„λ‘œ, 두 μ—”ν‹°ν‹° κ°„μ˜ 관계λ₯Ό λͺ…ν™•νžˆ ν•˜κ³  객체 κ·Έλž˜ν”„ 탐색이 더 μ‰¬μ›Œμ§‘λ‹ˆλ‹€.
    • ν•˜μ§€λ§Œ μ–‘λ°©ν–₯ μ—°κ΄€κ΄€κ³„λŠ” μ„œλ‘œ μ°Έμ‘°ν•˜λ©΄μ„œ λ³΅μž‘μ„±μ΄ μ¦κ°€ν•˜κ³ , 데이터 직렬화 κ³Όμ •μ—μ„œ λ¬΄ν•œ 루프가 λ°œμƒν•  수 μžˆμœΌλ―€λ‘œ μ‹ μ€‘ν•˜κ²Œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

πŸ™‹β€β™‚οΈ 데이터 직렬화(Serialization)

데이터 직렬화(Serialization)λŠ” 객체 λ˜λŠ” 데이터 ꡬ쑰λ₯Ό μ €μž₯ν•˜κ±°λ‚˜ 전솑할 수 μžˆλŠ” ν˜•μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” 과정을 μ˜λ―Έν•©λ‹ˆλ‹€.
이λ₯Ό 톡해 λ©”λͺ¨λ¦¬μ—μ„œ 객체둜 μ‘΄μž¬ν•˜λŠ” 데이터λ₯Ό 파일둜 μ €μž₯ν•˜κ±°λ‚˜ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 λ‹€λ₯Έ μ‹œμŠ€ν…œμœΌλ‘œ 전솑할 수 μžˆμŠ΅λ‹ˆλ‹€.
λ°˜λŒ€λ‘œ, 역직렬화(Deserialization)λŠ” μ§λ ¬ν™”λœ 데이터λ₯Ό λ‹€μ‹œ μ›λž˜μ˜ κ°μ²΄λ‚˜ 데이터 ꡬ쑰둜 λ³΅μ›ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€.

3️⃣ 선택 κΈ°μ€€.

  • κ°€λŠ₯ν•˜λ©΄ 단방ν–₯ 연관관계λ₯Ό μš°μ„ μœΌλ‘œ μ„€κ³„ν•˜κ³ , μ–‘λ°©ν–₯ 연관관계가 λ°˜λ“œμ‹œ ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ„€μ •ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

2️⃣ μ—°κ΄€κ΄€κ³„μ˜ 주인(Owning Side)

  • μ–‘λ°©ν–₯ μ—°κ΄€κ΄€κ³„μ—μ„œλŠ” μ™Έλž˜ ν‚€(Foreign Key)λ₯Ό 관리할 μ—°κ΄€κ΄€κ³„μ˜ 주인을 λͺ…ν™•νžˆ 지정해야 ν•©λ‹ˆλ‹€.
  • μ—°κ΄€κ΄€κ³„μ˜ 주인은 λ°μ΄ν„°λ² μ΄μŠ€μ— μ‹€μ œ μ™Έλž˜ ν‚€(Foreign Key)λ₯Ό μ €μž₯ν•˜λŠ” μ—”ν‹°ν‹°λ‘œ, 주인이 μ•„λ‹Œ μ—”ν‹°ν‹°μ—μ„œ 연관관계λ₯Ό 섀정해도 λ°μ΄ν„°λ² μ΄μŠ€μ—λŠ” λ°˜μ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • 주인을 μ •ν™•ν•˜κ²Œ μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 데이터 λΆˆμΌμΉ˜κ°€ λ°œμƒν•  수 있으며, λ°μ΄ν„°λ² μ΄μŠ€μ— λΆˆν•„μš”ν•œ 쿼리가 λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

3️⃣ 지연 λ‘œλ”©(Lazy Loading)κ³Ό μ¦‰μ‹œ λ‘œλ”©(Eager Loading)

1️⃣ 지연 λ‘œλ”©(Lazy Loading).

  • μ—°κ΄€λœ μ—”ν‹°ν‹°λ₯Ό μ‹€μ œλ‘œ μ‚¬μš©ν•  λ•Œ 데이터λ₯Ό λ‘œλ“œν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.
  • 기본적으둜 μ—°κ΄€ κ΄€κ³„λŠ” 지연 λ‘œλ”©μ„ μ‚¬μš©ν•˜λŠ” 것이 μ„±λŠ₯상 μœ λ¦¬ν•˜λ©°, ν•„μš”ν•œ μˆœκ°„μ—λ§Œ 데이터λ₯Ό 가져와 μ„±λŠ₯을 μ΅œμ ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

2️⃣ μ¦‰μ‹œ λ‘œλ”©(Eager Loading).

  • μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•  λ•Œ μ—°κ΄€λœ λͺ¨λ“  데이터λ₯Ό μ¦‰μ‹œ λ‘œλ“œν•˜λŠ” λ°©μ‹μœΌλ‘œ, ν•„μš” μ΄μƒμœΌλ‘œ λ§Žμ€ 데이터λ₯Ό 가져와 N+1 문제λ₯Ό μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

3️⃣ 선택 κΈ°μ€€.

  • 일반적으둜 지연 λ‘œλ”©(Lazy Loading)을 기본으둜 ν•˜κ³ , μ„±λŠ₯에 큰 영ν–₯이 μ—†λŠ” κ²½μš°μ—λ§Œ μ¦‰μ‹œ λ‘œλ”©(Eager Loading)을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • μ¦‰μ‹œ λ‘œλ”©(Eager Loading)을 μ‚¬μš©ν•˜λ©΄ μ—°κ΄€λœ λͺ¨λ“  데이터λ₯Ό ν•œ λ²ˆμ— κ°€μ Έμ˜€λ―€λ‘œ, νŠΉμ • 쑰회 μ‹œ ν•œ 번의 쿼리둜 μ—¬λŸ¬ 데이터λ₯Ό 가져와야 ν•  λ•Œ μœ μš©ν•©λ‹ˆλ‹€.

4️⃣ 페치 쑰인(Fetch Join)

1️⃣ 지연 λ‘œλ”©(Lazy Loading)μ—μ„œμ˜ 페치 쑰인(Fetch Join)

  • 지연 λ‘œλ”©(Lazy Loading)μ—μ„œ N+1 문제λ₯Ό λ°©μ§€ν•˜κ³  ν•„μš”ν•œ 데이터λ₯Ό ν•œ λ²ˆμ— κ°€μ Έμ˜€κΈ° μœ„ν•΄ 페치 쑰인(Fetch Join)을 μ‚¬μš©ν•©λ‹ˆλ‹€.

2️⃣ JPQL μΏΌλ¦¬μ—μ„œ 페치 쑰인(Fetch Join)

  • 페치 쑰인(Fetch Join)은 JPQL μΏΌλ¦¬μ—μ„œ μ—°κ΄€λœ 데이터λ₯Ό μ‘°μΈν•˜μ—¬ ν•¨κ»˜ λ‘œλ“œν•˜λŠ” λ°©μ‹μœΌλ‘œ, μ„±λŠ₯ μ΅œμ ν™”μ— μœ μš©ν•©λ‹ˆλ‹€.
  • 3️⃣ 선택 κΈ°μ€€.

  • 페치 쑰인(Fetch Join)은 ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ‚¬μš©ν•˜λ©°, 쿼리 λ³΅μž‘μ„±μ„ μ¦κ°€μ‹œν‚€λ―€λ‘œ λ¬΄λΆ„λ³„ν•˜κ²Œ μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘ μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

5️⃣ Cascade μ˜΅μ…˜κ³Ό orphanRemoval

1️⃣ Cascade μ˜΅μ…˜.

  • λΆ€λͺ¨ μ—”ν‹°ν‹°μ—μ„œ μžμ‹ μ—”ν‹°ν‹°λ₯Ό ν•¨κ»˜ 관리할 수 μžˆλ„λ‘ CascadeType.PERSIST, CascadeType.REMOVE λ“±μ˜ μ˜΅μ…˜μ„ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 예λ₯Ό λ“€μ–΄, λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•  λ•Œ μžμ‹ 엔티티도 μžλ™μœΌλ‘œ μ €μž₯λ˜κ±°λ‚˜ μ‚­μ œν•  λ•Œ μžμ‹ 엔티티도 ν•¨κ»˜ μ‚­μ œλ  수 μžˆμŠ΅λ‹ˆλ‹€.

2️⃣ orphanRemoval μ˜΅μ…˜.

  • λΆ€λͺ¨μ™€μ˜ 관계가 끊긴 μžμ‹ μ—”ν‹°ν‹°λ₯Ό μžλ™μœΌλ‘œ μ‚­μ œν•˜λ„λ‘ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • 예λ₯Ό λ“€μ–΄, λΆ€λͺ¨ μ—”ν‹°ν‹°μ—μ„œ μžμ‹ μ—”ν‹°ν‹° λ¦¬μŠ€νŠΈμ—μ„œ 제거되면 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œλ„ μžλ™μœΌλ‘œ μ‚­μ œλ©λ‹ˆλ‹€.

3️⃣ 선택 κΈ°μ€€.

  • Cascade와 orphanRemoval은 λΆ€λͺ¨μ™€ μžμ‹ κ°„ 생λͺ… μ£ΌκΈ°κ°€ μ™„μ „νžˆ μΌμΉ˜ν•  λ•Œλ§Œ μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
    • 그렇지 μ•ŠμœΌλ©΄ μ˜λ„μΉ˜ μ•Šμ€ 데이터 μ‚­μ œλ‚˜ μ˜μ†μ„± μ „νŒŒ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ™‹β€β™‚οΈ μ˜μ†μ„± μ „νŒŒ(Persistence Propagation)

JPAμ—μ„œ ν•˜λ‚˜μ˜ 엔티티에 μˆ˜ν–‰ν•œ μ˜μ†μ„± μž‘μ—…μ΄ μ—°κ΄€λœ λ‹€λ₯Έ 엔티티에 μžλ™μœΌλ‘œ μ „νŒŒλ˜λŠ” κΈ°λŠ₯을 μ˜λ―Έν•©λ‹ˆλ‹€.
이λ₯Ό 톡해 λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ νŠΉμ • μ˜μ†μ„± μƒνƒœ(예: μ €μž₯, μ‚­μ œ, 병합 λ“±)둜 변경될 λ•Œ, μžμ‹ 엔티티도 λ™μΌν•œ μƒνƒœλ‘œ 전이될 수 μžˆλ„λ‘ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

JPAμ—μ„œλŠ” 이λ₯Ό μœ„ν—€ Cascade μ˜΅μ…˜μ„ μ œκ³΅ν•˜λ©°, 주둜 μ—°κ΄€λœ μ—¬λŸ¬ μ—”ν‹°ν‹°κ°€ ν•˜λ‚˜μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό κ°€μ§ˆ λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.
즉, λΆ€λͺ¨μ™€ μžμ‹ 관계λ₯Ό 가진 μ—”ν‹°ν‹°κ°€ μžˆμ„ λ•Œ, λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό μ˜μ† μƒνƒœλ‘œ λ§Œλ“€κ±°λ‚˜ μ‚­μ œν•˜λ©΄, μžμ‹ 엔티티도 같은 μž‘μ—…μ΄ μžλ™μœΌλ‘œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

6️⃣ 데이터 쑰회 μ‹œ μ΅œμ ν™”.

  • 연관관계λ₯Ό 톡해 객체 κ·Έλž˜ν”„λ₯Ό 탐색할 λ•Œ λΆˆν•„μš”ν•œ 데이터가 κ³Όλ„ν•˜κ²Œ μ‘°νšŒλ˜μ§€ μ•Šλ„λ‘ JPQL, λ„€μ΄ν‹°λΈŒ SQL, DTO 등을 ν™œμš©ν•΄ ν•„μš”ν•œ λ°μ΄ν„°λ§Œ κ°€μ Έμ˜€λŠ” 방법을 κ³ λ €ν•΄μ•Ό ν•©λ‹ˆλ‹€.

1️⃣ DTOλ₯Ό μ‚¬μš©ν•œ 데이터 전솑.

  • μ—”ν‹°ν‹°μ˜ λͺ¨λ“  데이터λ₯Ό ν΄λΌμ΄μ–ΈνŠΈλ‘œ λ³΄λ‚΄λŠ” λŒ€μ‹ , ν•„μš”ν•œ μ •λ³΄λ§Œ 담은 DTO(Data Transfer Object)λ₯Ό 톡해 μ„±λŠ₯을 μ΅œμ ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

7️⃣ 연관관계 섀정이 λ°˜λ“œμ‹œ ν•„μš”ν•œμ§€ κ²€ν† .

  • λͺ¨λ“  관계λ₯Ό μ—°κ΄€κ΄€κ³„λ‘œ μ„€μ •ν•  ν•„μš”λŠ” μ—†μŠ΅λ‹ˆλ‹€.
    • λ‹¨μˆœνžˆ ID만 ν•„μš”ν•˜κ±°λ‚˜ λ‹€λ₯Έ ν…Œμ΄λΈ”μ—μ„œ νŠΉμ • 데이터λ₯Ό μ‘°νšŒν•  λ•Œλ§ˆλ‹€ μ‚¬μš©λ˜λŠ” 관계라면, ꡳ이 연관관계λ₯Ό μ„€μ •ν•˜μ§€ μ•Šκ³  IDλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‘°νšŒν•˜λŠ” 것이 μ„±λŠ₯상 μœ λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ°μ΄ν„°λ² μ΄μŠ€μ˜ 관계λ₯Ό λͺ¨λ“  μ—”ν‹°ν‹° κ°„ μ—°κ΄€κ΄€κ³„λ‘œ μ„€μ •ν•˜λ©΄ 였히렀 섀계가 λ³΅μž‘ν•΄μ§€κ³  μ„±λŠ₯을 ν•΄μΉ  수 μžˆμŠ΅λ‹ˆλ‹€.

8️⃣ 데이터 일관성 및 무결성 관리.

  • 연관관계λ₯Ό 톡해 데이터 일관성을 μœ μ§€ν•  수 μžˆλ„λ‘, νŠΈλžœμž­μ…˜ 관리와 μ—°κ΄€ 관계 섀정을 μ‹ μ€‘ν•˜κ²Œ ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • μžμ‹ μ—”ν‹°ν‹°κ°€ λΆ€λͺ¨ 엔티티에 κ°•ν•˜κ²Œ μ’…μ†λœ 경우(예: μ£Όλ¬Έκ³Ό μ£Όλ¬Έ ν•­λͺ©)μ—λŠ” 일관성을 μœ μ§€ν•  수 μžˆλ„λ‘ 연관관계λ₯Ό μ μ ˆν•˜κ²Œ μ„€μ •ν•˜κ³ , Cascade μ˜΅μ…˜μ„ 톡해 생λͺ… μ£ΌκΈ°λ₯Ό ν•¨κ»˜ κ΄€λ¦¬ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

9️⃣ μš”μ•½.

  • 연관관계λ₯Ό μ‚¬μš©ν•  λ•Œ κ³ λ €ν•΄μ•Ό ν•  사항은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
    • 단방ν–₯κ³Ό μ–‘λ°©ν–₯ 쀑 ν•„μš”ν•œ 방식을 μ„ νƒν•˜κ³ , μ–‘λ°©ν–₯ κ΄€κ³„μ˜ 경우 λ°˜λ“œμ‹œ 주인을 λͺ…ν™•νžˆ μ„€μ •ν•©λ‹ˆλ‹€.
    • 지연 λ‘œλ”©(Lazy Loading)을 기본으둜 μ‚¬μš©ν•˜λ©° ν•„μš”ν•  λ•Œλ§Œ μ¦‰μ‹œ λ‘œλ”©(Eager Loding)μ΄λ‚˜ 페치 쑰인(Fetch Join)을 μ‚¬μš©ν•©λ‹ˆλ‹€.
    • Cascade μ˜΅μ…˜κ³Ό orphanRemoval을 μ‹ μ€‘ν•˜κ²Œ μ„€μ •ν•˜μ—¬ λΆ€λͺ¨-μžμ‹ 관계λ₯Ό κ΄€λ¦¬ν•˜κ³ , μ˜λ„ν•˜μ§€ μ•Šμ€ 데이터 μ‚­μ œλ₯Ό λ°©μ§€ν•©λ‹ˆλ‹€.
    • μ„±λŠ₯을 κ³ λ €ν•˜μ—¬ 데이터 쑰회 μ‹œ μ΅œμ ν™”ν•˜κ³ , ν•„μš”ν•˜μ§€ μ•Šμ€ κ΄€κ³„λŠ” μ—°κ΄€κ΄€κ³„λŠ” μ„€μ •ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.