Post

[JPA] ν”„λ‘μ‹œ(Proxy)

πŸ“Œ λ“€μ–΄κ°€λ©°

JPA의 μ§€μ—° λ‘œλ”©μ€ ν”„λ‘μ‹œ(Proxy) 객체 μœ„μ—μ„œ λ™μž‘ν•œλ‹€. ν”„λ‘μ‹œλŠ” μ‹€μ œ μ—”ν‹°ν‹°λ₯Ό λŒ€μ‹ ν•˜λŠ” κ°€μ§œ 객체둜, μ‹€μ œλ‘œ μ‚¬μš©λ  λ•Œ μ΄ˆκΈ°ν™”λ˜μ–΄ μ§„μ§œ 엔티티에 μ ‘κ·Όν•œλ‹€.

em.getReference()λŠ” μ‹€μ œ μ—”ν‹°ν‹°κ°€ μ•„λ‹ˆλΌ ν”„λ‘μ‹œ 객체λ₯Ό λ°˜ν™˜ν•œλ‹€. (em.find()λŠ” μ‹€μ œ μ—”ν‹°ν‹°)


1. ν”„λ‘μ‹œμ˜ νŠΉμ§• β€” ν•œ 번만 μ΄ˆκΈ°ν™”

1
2
3
4
5
6
Member findMember = em.getReference(Member.class, member.getId());

System.out.println(findMember.getClass());     // ν”„λ‘μ‹œ 객체
System.out.println(findMember.getId());        // 쿼리 μ•ˆ λ‚˜κ° (idλŠ” 이미 μ•Ž)
System.out.println(findMember.getUsername());  // β˜… μ—¬κΈ°μ„œ 쿼리 λ°œμƒ! (μ‹€μ œ κ°’ ν•„μš”)
System.out.println(findMember.getClass());     // μ—¬μ „νžˆ ν”„λ‘μ‹œ!

πŸ’‘ ν”„λ‘μ‹œλŠ” 처음 μ‚¬μš©ν•  λ•Œ ν•œ 번만 μ΄ˆκΈ°ν™”λœλ‹€. μ€‘μš”ν•œ 건, ν”„λ‘μ‹œκ°€ μ‹€μ œ μ—”ν‹°ν‹°λ‘œ λ°”λ€ŒλŠ” 게 μ•„λ‹ˆλΌ μ‹€μ œ 엔티티에 μ ‘κ·Όν•  수 있게 λ§ν¬λ˜λŠ” 것이닀. getReference()둜 κ°€μ Έμ˜¨ κ°μ²΄λŠ” μ΄ˆκΈ°ν™” 후에도 계속 ν”„λ‘μ‹œλ‹€.


2. ⚠️ νƒ€μž… λΉ„κ΅λŠ” instanceof

ν”„λ‘μ‹œ λ•Œλ¬Έμ— == 비ꡐ가 μ˜ˆμƒκ³Ό λ‹€λ₯΄κ²Œ λ‚˜μ˜¬ 수 μžˆλ‹€.

1
2
3
4
5
// λ‘˜ λ‹€ find β†’ 같은 μ‹€μ œ μ—”ν‹°ν‹° 클래슀
em.find(...).getClass() == em.find(...).getClass()          // true

// find vs getReference β†’ μ‹€μ œ μ—”ν‹°ν‹° vs ν”„λ‘μ‹œ
em.find(...).getClass() == em.getReference(...).getClass()  // false!

⚠️ κ·Έλž˜μ„œ νƒ€μž… λΉ„κ΅λŠ” ==κ°€ μ•„λ‹ˆλΌ instanceofλ₯Ό 써야 ν•œλ‹€.

1
2
findMember  instanceof Member   // true (μ‹€μ œλ“  ν”„λ‘μ‹œλ“ )
findMember2 instanceof Member   // true

3. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ ν”„λ‘μ‹œ

상황결과
이미 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ—”ν‹°ν‹°κ°€ 있으면getReference()도 μ‹€μ œ μ—”ν‹°ν‹° λ°˜ν™˜
이미 ν”„λ‘μ‹œκ°€ 있으면find()도 ν”„λ‘μ‹œ λ°˜ν™˜

πŸ’‘ JPAλŠ” 같은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 같은 μ‹λ³„μžλ©΄ 항상 같은 객체(==)μž„μ„ 보μž₯ν•œλ‹€. κ·Έλž˜μ„œ 이미 μžˆλŠ” 것과 νƒ€μž…μ„ λ§žμΆ”λ € ν•œλ‹€. (find λ¨Όμ €λ©΄ μ‹€μ œ, getReference λ¨Όμ €λ©΄ ν”„λ‘μ‹œλ‘œ 톡일)


4. ⚠️ μ€€μ˜μ† μƒνƒœμ˜ ν”„λ‘μ‹œ μ΄ˆκΈ°ν™”

1
2
3
Member findMember = em.getReference(Member.class, member.getId());
em.detach(findMember);              // μ€€μ˜μ† μƒνƒœλ‘œ
String username = findMember.getUsername();   // β˜… μ˜ˆμ™Έ λ°œμƒ!
1
2
org.hibernate.LazyInitializationException:
    could not initialize proxy - no Session

⚠️ ν”„λ‘μ‹œ μ΄ˆκΈ°ν™”λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 관리가 ν•„μš”ν•˜λ‹€. detach/clear/νŠΈλžœμž­μ…˜ μ’…λ£Œ λ“±μœΌλ‘œ μ€€μ˜μ† μƒνƒœκ°€ 되면 μ΄ˆκΈ°ν™” μ‹œ LazyInitializationException이 λ°œμƒν•œλ‹€.


5. ν”„λ‘μ‹œ μƒνƒœ ν™•μΈΒ·κ°•μ œ μ΄ˆκΈ°ν™”

1
2
3
4
5
6
7
// μ΄ˆκΈ°ν™” μ—¬λΆ€ 확인
emf.getPersistenceUnitUtil().isLoaded(findMember);   // false
findMember.getUsername();                            // μ΄ˆκΈ°ν™” λ°œμƒ
emf.getPersistenceUnitUtil().isLoaded(findMember);   // true

// κ°•μ œ μ΄ˆκΈ°ν™”
Hibernate.initialize(findMember);

πŸ“ 정리

1
2
3
4
5
6
JPA ν”„λ‘μ‹œ
β”œβ”€ νŠΉμ§•   ν•œ 번만 μ΄ˆκΈ°ν™”, getReference()κ°€ λ°˜ν™˜
β”œβ”€ 본질   μ‹€μ œ μ—”ν‹°ν‹°λ‘œ λ°”λ€Œμ§€ μ•Šκ³  'μ ‘κ·Ό'만 κ°€λŠ₯
β”œβ”€ 비ꡐ   == λŒ€μ‹  instanceof μ‚¬μš©
β”œβ”€ μ»¨ν…μŠ€νŠΈ  같은 μ‹λ³„μžλ©΄ 같은 객체둜 톡일
└─ 주의   μ€€μ˜μ† μƒνƒœ μ΄ˆκΈ°ν™” β†’ LazyInitializationException
κ°œλ…ν•œ 쀄 μ •μ˜
ν”„λ‘μ‹œμ‹€μ œ μ—”ν‹°ν‹°λ₯Ό λŒ€μ‹ ν•˜λŠ” κ°€μ§œ 객체
getReferenceν”„λ‘μ‹œλ₯Ό λ°˜ν™˜
instanceofν”„λ‘μ‹œ/μ‹€μ œ λ¬΄κ΄€ν•˜κ²Œ νƒ€μž… 비ꡐ
LazyInitializationExceptionμ€€μ˜μ† ν”„λ‘μ‹œ μ΄ˆκΈ°ν™” μ‹€νŒ¨

ν”„λ‘μ‹œλŠ” μ§€μ—° λ‘œλ”©μ˜ 핡심 λ©”μ»€λ‹ˆμ¦˜μ΄λ‹€. β€œν”„λ‘μ‹œλŠ” μ‹€μ œ μ—”ν‹°ν‹°λ‘œ λ°”λ€Œμ§€ μ•ŠλŠ”λ‹€β€λŠ” 점, κ·Έλž˜μ„œ νƒ€μž… λΉ„κ΅λŠ” instanceof둜 ν•΄μ•Ό ν•œλ‹€λŠ” 점, 그리고 μ€€μ˜μ† μƒνƒœμ—μ„œ μ΄ˆκΈ°ν™”ν•˜λ©΄ μ˜ˆμ™Έκ°€ λ‚œλ‹€λŠ” 점만 작으면 μ§€μ—° λ‘œλ”©μ„ μ•ˆμ „ν•˜κ²Œ λ‹€λ£° 수 μžˆλ‹€.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.