1 λΆ„ μ†Œμš”

1. λ°œμƒ

κΉ€μ˜ν•œ κ°œλ°œμžλ‹˜μ˜ JPA μ‹œλ¦¬μ¦ˆ μˆ˜κ°• ν›„ λ³΅μŠ΅μ„ κ²Έν•˜μ—¬ 개인 ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ˜ 도쀑 낯이 읡은 μ˜ˆμ™Έκ°€ λ°œμƒν–ˆλ‹€.

λ°”λ‘œ could not initialize proxy - no Session μ˜ˆμ™ΈμΈλ°, κ΄€λ ¨ 정보λ₯Ό 찾아보닀 λ³΄λ‹ˆ JPA 기본편 μˆ˜μ—…μ—μ„œ ν•΄λ‹Ή μ—λŸ¬μ— λŒ€ν•΄ β€˜JPAλ₯Ό μ‚¬μš©ν•΄μ„œ κ°œλ°œν•˜μ‹œλ‹€ 보면 λ°˜λ“œμ‹œ ν•œλ²ˆμ€ 마주칠 μ—λŸ¬β€™ 라고 λ§μ”€ν•˜μ…¨λ˜ λ‚΄μš©μ΄ 기얡이 λ– μ˜¬λžλ‹€.

막상 처음 μ—λŸ¬λ₯Ό λ°œκ²¬ν•˜κ³  λ‚˜μ„œλŠ” κ°•μ˜μ—μ„œ λ“€μ—ˆλ˜ λ‚΄μš©μ΄ 기얡이 κ°€λ¬Όκ°€λ¬Ό ν–ˆμ—ˆλ˜ 터라 ν•œλ²ˆ 정리λ₯Ό ν•΄λ‘κ³ μž 기둝을 남긴닀.

2. 원인

2-1. ν•΄λ‹Ή μ—λŸ¬μ˜ 원인

μ—λŸ¬μ˜ 원인은 λ‹€μŒκ³Ό κ°™λ‹€.

  1. μ—”ν‹°ν‹°μ˜ 쑰인 κ΄€κ³„μ—μ„œ 지연 λ‘œλ”©μ„ μ‚¬μš©ν•˜λŠ” ν•„λ“œ(FetchType.LAZY) κ°€ μžˆλŠ” μ—”ν‹°ν‹°λ₯Ό 쑰회 μ‹œ, ν•΄λ‹Ή μ—”ν‹°ν‹° 객체의 ν”„λ‘μ‹œ 객체가 λ°˜ν™˜λœλ‹€.

  2. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ²”μœ„ λ°–μ—μ„œ μœ„μ˜ ν”„λ‘μ‹œ 객체가 쑰인 된 μ—°κ΄€ 관계 ν•„λ“œλ₯Ό μ‘°νšŒν•˜λ €κ³  ν•˜λ©΄ ν•΄λ‹Ή μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

FechType.LAZY μƒνƒœμ—μ„œ 쑰인 ν•„λ“œ ν¬ν•¨ν•˜μ—¬ 쑰회 μ‹œ!
μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ°– (ex: Controller) μ—μ„œ ν”„λ‘μ‹œ 객체 쑰인 ν•„λ“œ 쑰회 μ‹œ

2-2. μ—λŸ¬ λ°œμƒ μ‹œ 상황

  1. μ—λŸ¬κ°€ λ°œμƒν•œ λΆ€λΆ„μ˜ μ—”ν‹°ν‹° μ—°κ΄€ κ΄€κ³„λŠ” νšŒμ›κ³Ό νšŒμ›-κ·Έλ£Ή (1:N) 관계이닀.
  2. νŠΉμ • API μš”μ²­ μ‹œ Filter μ—μ„œ 인가(Authorization) ν† ν°μœΌλ‘œ νšŒμ›μ— κ΄€ν•œ μ†Œμ† κ·Έλ£Ή 정보λ₯Ό μ‘°νšŒν•œλ‹€.
  3. μš”μ²­ μŠ€λ ˆλ“œ μ»¨ν…μŠ€νŠΈμ— νšŒμ› 정보λ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•΄ Entity 정보λ₯Ό DTO 둜 λ³€ν™˜ ν•œλ‹€.
  4. DTO λ³€ν™˜ κ³Όμ •μ—μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό λΉ μ Έλ‚˜μ˜¨ μ—”ν‹°ν‹° ν”„λ‘μ‹œ 객체가 μ†Œμ† κ·Έλ£Ή 정보λ₯Ό μš”μ²­ν•œλ‹€.

3. ν•΄κ²° 방법

κ²°κ΅­ μœ„ 였λ₯˜λŠ” ν”„λ‘μ‹œ 객체가 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ²”μœ„ λ°–μ—μ„œ 지연 λ‘œλ”© ν•„λ“œμ˜ 값을 μš”μ²­ ν–ˆμ„ λ•Œ λ°œμƒν•˜λŠ” 였λ₯˜μ΄λ―€λ‘œ ν•΄κ²° 방법은 크게 μ„Έκ°€μ§€λ‘œ λ‚˜λˆŒ 수 μžˆλ‹€.

3-1. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ²”μœ„ λ‚΄μ—μ„œ ν•„μš”ν•œ 값을 μ‚¬μš©ν•œλ‹€. (μœ„ κ²½μš°μ—λŠ” DTO λ³€ν™˜)

ꡬ쑰적으둜 κΉ”λ”ν•΄μ§€λŠ” 이점은 μžˆκ² μ§€λ§Œ, λ§Œμ•½ 자주 ν˜ΈμΆœλ˜λŠ” 쿼리라면 ν˜ΈμΆœμ‹œλ§ˆλ‹€ LAZY νƒ€μž…μ˜ ν•„λ“œλ₯Ό λ°˜λ³΅ν•΄μ„œ μΆ”κ°€λ‘œ μ‘°νšŒν•˜λŠ” N+1 λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆλ‹€.

3-2. FetchType 을 EAGER 둜 λ³€κ²½ν•œλ‹€. (ν”„λ‘μ‹œ 객체 μ‚¬μš© X)

ν•„λ“œ FetchType 자체λ₯Ό λ°”κΎΈμ–΄ λ²„λ¦¬λŠ” 방법인데, μ΄λŠ” ν•΄λ‹Ή μ—°κ΄€ 관계 ν•„λ“œμ˜ 쑰인 정보가 ν•„μš” μ—†λŠ” κ²½μš°μ—λ„ κ³„μ†ν•΄μ„œ Join 으둜 데이터λ₯Ό κ°€μ Έμ˜€κΈ° λ•Œλ¬Έμ— λΆˆν•„μš”ν•œ μ†Œμš”λ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆλ‹€.

3-3. FetchJoin 을 μ‚¬μš©ν•œλ‹€.

κ°€μž₯ 적은 μˆ˜μ • λ²”μœ„ λ‚΄μ—μ„œ μ—¬λŸ¬ 문제λ₯Ό λ™μ‹œμ— ν•΄κ²°ν•  수 μžˆλŠ” 방법이닀.  순수 Jpa 의 경우 JPQL λ¬Έλ²•μ—μ„œ join λŒ€μ‹  join fetch λ₯Ό, data jpa μ‚¬μš©μ‹œμ—λŠ” @EntityGraph μ• λ…Έν…Œμ΄μ…˜μ„, QueryDSL μ‚¬μš©μ‹œμ—λŠ” .fetchJoin() λ©”μ„œλ“œ 체이닝을 톡해 적용 κ°€λŠ₯ν•˜λ‹€.

νƒœκ·Έ: ,

μΉ΄ν…Œκ³ λ¦¬:

μ—…λ°μ΄νŠΈ: