Skip to content

Latest commit

Β 

History

History

2-persistence-context

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Β 
Β 

[JPA #2] μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ (Persistence Context)

Tistory λΈ”λ‘œκ·Έ ν¬μŠ€νŒ… λ°”λ‘œκ°€κΈ°

JPA의 Persistence Context(μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ)λž€ μ—”ν‹°ν‹°λ₯Ό 영ꡬ μ €μž₯ν•˜λŠ” ν™˜κ²½μž…λ‹ˆλ‹€.

JPAλŠ” μ—”ν‹°ν‹° 관리λ₯Ό μœ„ν•΄ μ—¬λŸ¬κ°€μ§€ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ”λ° κ·Έ 기반이 λ˜λŠ” 것이 λ°”λ‘œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μž…λ‹ˆλ‹€. (κ°€μž₯ μ€‘μš”)

JPAλŠ” μ—”ν‹°ν‹°λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€κ°€ μ•„λ‹Œ μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό 톡해 μ ‘κ·Ό κ°€λŠ₯ν•œ νŠΉμ • ν™˜κ²½μ— μ €μž₯ν•œ λ’€ μ‚¬μš©ν•©λ‹ˆλ‹€.

이λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ—”ν‹°ν‹°μ˜ 생λͺ…주기에 λŒ€ν•΄ μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€.

μ—”ν‹°ν‹°μ˜ 생λͺ…μ£ΌκΈ°

μ—”ν‹°ν‹°μ˜ 생λͺ…μ£ΌκΈ°μ—λŠ” λΉ„μ˜μ†, μ˜μ†, μ€€μ˜μ†, μ‚­μ œ μ΄λ ‡κ²Œ 4가지가 μžˆμŠ΅λ‹ˆλ‹€.

  1. λΉ„μ˜μ† (new/transient)

λΉ„μ˜μ† μƒνƒœλž€, μ—”ν‹°ν‹° 객체λ₯Ό 생성은 ν–ˆμ§€λ§Œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€λŠ” 관계가 μ „ν˜€ μ—†λŠ” μ™„μ „νžˆ μƒˆλ‘œμš΄ μƒνƒœλ₯Ό λœ»ν•©λ‹ˆλ‹€.

  1. μ˜μ† (managed)

μƒμ„±ν•œ μ—”ν‹°ν‹° 객체λ₯Ό μƒμ„±ν•œ λ’€ μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό 톡해 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μƒνƒœλ₯Ό λœ»ν•©λ‹ˆλ‹€.

μ—”ν‹°ν‹° λ§€λ‹ˆμ €μ˜ persist λ©”μ„œλ“œλ₯Ό 톡해 객체λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— 등둝할 수 μžˆμŠ΅λ‹ˆλ‹€.

객체λ₯Ό μƒˆλ‘œ 생성할 λ•Œλ„ μ˜μ† μƒνƒœλ₯Ό λ§Œλ“€μ–΄μ€„ 수 μžˆμ§€λ§Œ, 이미 λ°μ΄ν„°λ² μ΄μŠ€μ— μ‘΄μž¬ν•˜λŠ” λ°μ΄ν„°μ˜ κ²½μš°μ—λ„ μ˜μ† μƒνƒœλ₯Ό λ§Œλ“€μ–΄μ€„ 수 μžˆμŠ΅λ‹ˆλ‹€.

νŠΉμ • 객체 쑰회 μ‹œ μ˜μ† μƒνƒœκ°€ μ•„λ‹ˆλΌλ©΄ DB 쑰회λ₯Ό 톡해 1μ°¨ μΊμ‹œμ— λ“±λ‘ν•΄μ„œ μ˜μ† μƒνƒœλ₯Ό λ§Œλ“€μ–΄μ€λ‹ˆλ‹€. (1μ°¨ μΊμ‹œμ— λŒ€ν•œ 뢀뢄은 μ•„λž˜μ—μ„œ 쑰금 더 μžμ„Ένžˆ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.)

μ˜μ† μƒνƒœκ°€ λœλ‹€κ³  ν•΄μ„œ DB 쿼리가 λ°”λ‘œ λ‚ λΌκ°€λŠ” 것이 μ•„λ‹ˆκ³  νŠΈλžœμž­μ…˜μ˜ 컀밋 μ‹œμ μ— DB 쿼리가 λ‚ λΌκ°‘λ‹ˆλ‹€.

  1. μ€€μ˜μ† (detached)

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό 톡해 κ΄€λ¦¬λ˜κ³  μžˆλŠ” μ—”ν‹°ν‹° 객체가 λΆ„λ¦¬λœ μƒνƒœλ₯Ό λœ»ν•©λ‹ˆλ‹€.

μ€€μ˜μ† μƒνƒœκ°€ 되면 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯듀을 μ‚¬μš©ν•  수 μ—†κΈ° λ•Œλ¬Έμ— 거의 μ‚¬μš©ν•  일이 μ—†μŠ΅λ‹ˆλ‹€.

  1. μ‚­μ œ (removed)

이름 κ·ΈλŒ€λ‘œ μ‚­μ œλœ μƒνƒœλ₯Ό λœ»ν•©λ‹ˆλ‹€.


μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 이점

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ–΄λ–€ 이점듀을 μ œκ³΅ν•˜λŠ”μ§€ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

1μ°¨ μΊμ‹œ

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ‚΄λΆ€μ—λŠ” 1μ°¨ μΊμ‹œκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

객체가 μ˜μ†μƒνƒœκ°€ 되면 1μ°¨ μΊμ‹œμ— key, value ν˜•νƒœλ‘œ λ“±λ‘λ©λ‹ˆλ‹€.

μ—¬κΈ°μ„œ keyλŠ” pk둜 λ§΅ν•‘ν•œ 값이고, 값은 μ €μž₯ν•œ μ—”ν‹°ν‹° 객체 μžμ²΄κ°€ λ©λ‹ˆλ‹€.

JPAλŠ” 쑰회 μ‹œ DB μ‘°νšŒμ— μ•žμ„œ 1μ°¨ μΊμ‹œλ₯Ό λ¨Όμ € ν™•μΈν•˜κΈ° λ•Œλ¬Έμ—, 1μ°¨ μΊμ‹œμ— μ‘°νšŒν•˜κ³ μž ν•˜λŠ” μ—”ν‹°ν‹° 객체가 μ‘΄μž¬ν•œλ‹€λ©΄ DBκΉŒμ§€ 갈 ν•„μš”μ—†μ΄ 1μ°¨ μΊμ‹œμ—μ„œ ν•΄λ‹Ή 객체λ₯Ό κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

이 κ³Όμ •μ—μ„œ λ§Œμ•½ 쑰회 μ‹œ 1μ°¨ μΊμ‹œμ— μ›ν•˜λŠ” μ—”ν‹°ν‹° 객체가 μ—†λ‹€λ©΄, DBμ—μ„œ 가져와 1μ°¨ μΊμ‹œμ— μ €μž₯ ν›„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

이후에 같은 객체 쑰회 μ‹œ 1μ°¨ μΊμ‹œμ— μ €μž₯ν•œ 객체λ₯Ό λ°˜ν™˜ν•˜κ²Œ λ˜λŠ” 것이죠.

일반적으둜 μš°λ¦¬κ°€ μ•Œκ³  μžˆλŠ” μΊμ‹œμ˜ κ°œλ…κ³Ό κ°™μŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 이 1μ°¨ μΊμ‹œλΌλŠ” 것은 ν•˜λ‚˜μ˜ DB νŠΈλžœμž­μ…˜ λ‹¨μœ„ λ™μ•ˆλ§Œ μ‚΄μ•„ μžˆμŠ΅λ‹ˆλ‹€. 고객의 μš”μ²­ λ“€μ–΄μ™€μ„œ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직이 μ „λΆ€ μˆ˜ν–‰λœ ν›„ λλ‚˜λ²„λ¦¬λ©΄ μ‚¬λΌμ§€κ²Œ λ©λ‹ˆλ‹€.

κ·Έλž˜μ„œ λ™μ‹œμš”μ²­μ΄ λ§Žμ„ λ•Œμ˜ 큰 μ„±λŠ₯ κ°œμ„  νš¨κ³ΌλŠ” κΈ°λŒ€ν•˜κΈ°λŠ” μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

μ˜μ† μ—”ν‹°ν‹°μ˜ 동일성 보μž₯

JPAλŠ” 같은 νŠΈλžœμž­μ…˜μ—μ„œ μ‘°νšŒν•œ μ—”ν‹°ν‹°λ₯Ό λ‹€μ‹œ μ‘°νšŒν•  경우, μΊμ‹œ(1μ°¨ μΊμ‹œ)λ₯Ό 톡해 뢈러였기 λ•Œλ¬Έμ— λͺ‡ λ²ˆμ„ ν˜ΈμΆœν•˜λ˜ μΆ”κ°€ SQLλ¬Έ 호좜 없이도 같은 μ—”ν‹°ν‹°μž„μ„ 보μž₯ν•΄μ€λ‹ˆλ‹€.

1μ°¨ μΊμ‹œλ‘œ REPEATABLE READ 격리 μˆ˜μ€€μ„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ ˆλ²¨μ—μ„œ μ œκ³΅ν•΄μ£ΌλŠ” μ…ˆμ΄μ£ .

User user1 = em.find(User.class, 1L);
User user2 = em.find(User.class, 1L);

// 동일성 보μž₯ (true)
System.out.println(user1 == user2);

νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜λŠ” μ“°κΈ° 지연

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—λŠ” 1μ°¨ μΊμ‹œ 말고도 μ“°κΈ° 지연 SQL μ €μž₯μ†ŒλΌλŠ” 것이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

μ“°κΈ° 지연 μ €μž₯μ†ŒλŠ” SQL문듀을 λ“€κ³  μžˆλ‹€κ°€ νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ— ν•œλ²ˆμ— DB둜 μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.

INSERT 문을 각각 λ”°λ‘œ ν˜ΈμΆœν•˜λŠ” 것과, λͺ¨μ•„μ„œ batch insert ν•˜λŠ” κ²ƒμ˜ 차이인 것이죠.

μ—”ν‹°ν‹° 객체λ₯Ό persist ν•˜λ©΄, 1μ°¨ μΊμ‹œμ— μ €μž₯됨과 λ™μ‹œμ— ν•΄λ‹Ήν•˜λŠ” INSERT 문이 μ“°κΈ° 지연 μ €μž₯μ†Œμ— λ“±λ‘λ©λ‹ˆλ‹€.

λ§Œμ•½ μ—¬κΈ°μ„œ λ‹€λ₯Έ μ—”ν‹°ν‹° 객체λ₯Ό μΆ”κ°€λ‘œ persist ν•˜λ©΄, λ˜‘κ°™μ΄ 1μ°¨ μΊμ‹œμ— μΆ”κ°€λ˜κ³  μ“°κΈ° 지연 μ €μž₯μ†Œμ— INSERT 문이 μΆ”κ°€λ©λ‹ˆλ‹€.

그리고 μ΅œμ’…μ μœΌλ‘œ νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ΄ 였면 μ“°κΈ° 지연 μ €μž₯μ†Œμ— λͺ¨μ•„λ‘μ—ˆλ˜ SQL문듀을 ν•œλ²ˆμ— DB둜 flush ν•˜κ²Œ λ©λ‹ˆλ‹€.

μ‹€μ œ SQL문듀은 νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ— ν•œλ²ˆμ— λ‚ λΌκ°€κ²Œ λ˜λŠ” 것이죠.

κ·Έλ ‡λ‹€λ©΄ ν•œλ²ˆμ— λͺ‡κ°œμ˜ SQL문을 μ²˜λ¦¬ν•  수 μžˆλŠλƒμ— λŒ€ν•œ 것은 μ•„λž˜μ™€ 같이 batch_size 속성 섀정을 톡해 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

<property name="hibernate.jdbc.batch_size" value="10"/>

λ³€κ²½ 감지 (Dirty Checking)

JPA의 κ°€μž₯ 큰 μž₯점 쀑 ν•˜λ‚˜λŠ” 마치 μžλ°” μ»¬λ ‰μ…˜μ„ 닀루듯이 객체λ₯Ό λ‹€λ£° 수 μžˆλ‹€λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.

μ»¬λ ‰μ…˜μ— ν¬ν•¨λœ 객체의 ν•„λ“œ 값을 λ³€κ²½ν•  λ•ŒλŠ” κ°’ λ³€κ²½ 이후 λ‹€μ‹œ μ»¬λ ‰μ…˜μ— 넣어쀄 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. 객체의 참쑰값을 가지고 있기 λ•Œλ¬Έμ— ꡳ이 λ‹€μ‹œ μ €μž₯ν•΄μ£ΌλŠ” 과정을 κ±°μΉ  ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ΄μ£ .

JPAμ—μ„œλ„ λ§ˆμ°¬κ°€μ§€λ‘œ μ—”ν‹°ν‹° 객체의 값을 λ³€κ²½ν•  λ•Œ, 값을 λ³€κ²½ν•œ λ’€ λ‹€μ‹œ persist 해쀄 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

μžλ°” μ»¬λ ‰μ…˜μ—μ„œ ν•˜λŠ” 것 처럼 setterλ₯Ό 톡해 값을 λ³€κ²½ν•˜λ©΄ ν•΄λ‹Ή λ³€κ²½ 사항을 μ•Œμ•„μ„œ κ°μ§€ν•©λ‹ˆλ‹€.

JPAλŠ” 이런 dirty checking을 μ–΄λ–»κ²Œ κ°€λŠ₯ν•˜κ²Œ ν• κΉŒμš”?

1μ°¨ μΊμ‹œμ—λŠ” key, entity와 졜초 μ½μ–΄λ“€μ˜€μ„ λ‹Ήμ‹œ μŠ€λƒ…μƒ·μ΄ ν•¨κ»˜ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

μ΄λ•Œ νŠΈλžœμž­μ…˜ 컀밋에 μ˜ν•œ flushκ°€ λ°œμƒν•˜λ©΄ 엔티티와 μŠ€λƒ…μƒ·μ„ λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ 값이 μžˆλŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.

λ§Œμ•½ λ³€κ²½λœ λ‚΄μš©μ΄ μžˆλ‹€λ©΄ UPDATE 쿼리λ₯Ό μ“°κΈ° 지연 μ €μž₯μ†Œμ— μΆ”κ°€ν•©λ‹ˆλ‹€.

그런 λ’€ νŠΈλžœμž­μ…˜μ΄ μ»€λ°‹λ˜λŠ” μ‹œμ μ— μ“°κΈ° 지연 μ €μž₯μ†Œμ— 있던 쿼리듀과 같이 flush ν•©λ‹ˆλ‹€.

이런 dirty checking κΈ°λŠ₯이 제곡되기 λ•Œλ¬Έμ— κ°œλ°œμžκ°€ 직접 UPDATE 문의 ν•„μš” 유무λ₯Ό ꡳ이 μ½”λ“œλ‘œ 확인할 ν•„μš”κ°€ μ—†μ–΄μ§€κ²Œ λ˜λŠ” 것이죠. (μ‹€μˆ˜κ°€ μ€„μ–΄λ“œλŠ” νš¨κ³Όλ„ 있겠죠?)


Flush

사싀 μœ„μ—μ„œ flush에 λŒ€ν•œ 이야기λ₯Ό 이미 ν•˜κ³  μžˆμ–΄μ„œ flush에 λŒ€ν•œ λ‚΄μš©μ΄ λ¨Όμ € μ™”μ–΄μ•Ό 쒋지 μ•Šμ•˜λ‚˜ μ‹Άμ§€λ§Œ...

flushλž€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½λ‚΄μš©μ„ λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€.

flushκ°€ λ°œμƒν•˜λ©΄ dirty checking을 μ§„ν–‰ν•˜κ³ , dirty checking의 결과에 따라 μˆ˜μ •λœ 엔티티에 λŒ€ν•œ SQL문을 μ“°κΈ° 지연 μ €μž₯μ†Œμ— λ“±λ‘ν•©λ‹ˆλ‹€. 그리고 μ΅œμ’…μ μœΌλ‘œ μ“°κΈ° 지연 μ €μž₯μ†Œμ— μžˆλŠ” 쿼리듀을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ³΄λƒ…λ‹ˆλ‹€.

기본적으둜 flushλŠ” νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ— μžλ™μœΌλ‘œ μ‹€ν–‰λ˜μ§€λ§Œ, λ‹€λ₯Έ 방법듀도 μ‘΄μž¬ν•©λ‹ˆλ‹€.

μ‹€μ œλ‘œ μ΄λ ‡κ²Œ ν•  일은 λ“œλ¬Όμ§€λ§Œ em.flush() λ₯Ό 톡해 직접 flush ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ§Œμ•½ persist만 ν•œ μƒνƒœμ—μ„œ 쿼리λ₯Ό 직접 ν™•μΈν•˜κ³  싢은 κ²½μš°μ— μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μΆ”κ°€λ‘œ, flushλŠ” JPQL 쿼리λ₯Ό μ‹€ν–‰ν•  μ‹œ μžλ™μœΌλ‘œ ν˜ΈμΆœλ©λ‹ˆλ‹€.

μ •λ¦¬ν•˜μžλ©΄,

flushλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ–΄λ–€ 변경사항을 μΌμœΌν‚€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

νŠΈλžœμž­μ…˜ 컀밋 μ΄ν›„μ—λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ μ†Œλ©Έλ‘œ 인해 1μ°¨ μΊμ‹œλŠ” μ‚¬λΌμ§€κ²Œ λ˜μ§€λ§Œ, flush κ°€ 1μ°¨ μΊμ‹œμ— μ–΄λ–€ 변경사항을 μΌμœΌν‚€λŠ” 것은 μ•„λ‹ˆλΌλŠ” λœ»μž…λ‹ˆλ‹€.

flushλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½λ‚΄μš©μ„ DB에 λ™κΈ°ν™”ν•΄μ£ΌλŠ” μ—­ν• λ§Œ ν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€.


μ€€μ˜μ† μƒνƒœ

μœ„μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ 생λͺ…μ£ΌκΈ°λ₯Ό μ†Œκ°œν•˜λŠ” λΆ€λΆ„μ—μ„œ κ°„λ‹¨ν•˜κ²Œ μ–ΈκΈ‰ν–ˆμ§€λ§Œ,

μ€€μ˜μ† μƒνƒœλŠ” 기쑴에 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ‘œ κ΄€λ¦¬λ˜λ˜ μ—”ν‹°ν‹° 객체λ₯Ό λΆ„λ¦¬ν•΄μ„œ 더 이상 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ κ΄€λ¦¬λ˜μ§€ μ•ŠλŠ” μƒνƒœλ₯Ό λœ»ν•©λ‹ˆλ‹€.

μ€€μ˜μ† μƒνƒœλ‘œ λ§Œλ“œλŠ” 방법은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • em.detach(entity): νŠΉμ • μ—”ν‹°ν‹°λ§Œ μ€€μ˜μ† μƒνƒœλ‘œ μ „ν™˜
  • em.clear(): μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ΄ˆκΈ°ν™”
  • em.close(): μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ’…λ£Œ

μ„Έ 방법 쀑 μ–΄λ–€ 방식을 μ‚¬μš©ν•˜λ”λΌλ„ μ€€μ˜μ† μƒνƒœλΌλ©΄ μœ„μ—μ„œ μ •λ¦¬ν•œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 이점듀을 μ΄μš©ν•  수 μ—†κ²Œ λ©λ‹ˆλ‹€.


μ΄μƒμœΌλ‘œ JPA의 핡심인 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— λŒ€ν•œ 정리λ₯Ό λ§ˆμΉ©λ‹ˆλ‹€.