☘️ λ°±μ—”λ“œ: Backend

[Spring] JPA μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ΄ν•΄ν•˜κΈ°

🐀 쀀콩이 2023. 6. 27. 21:27

πŸ€” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλž€?

 

JPA μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ (Persistence Context) λž€ μ—”ν‹°ν‹°λ₯Ό 영ꡬ μ €μž₯ν•˜λŠ” ν™˜κ²½μ΄λΌλŠ” 뜻으둜, μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό λ°μ΄ν„°λ² μ΄μŠ€ μ‚¬μ΄μ—μ„œ μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜λŠ” 논리적인 μ˜μ—­μž…λ‹ˆλ‹€. EntityManager 둜 μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•˜κ±°λ‚˜ μ‘°νšŒν•˜λ©΄ EntityManager λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ—”ν‹°ν‹°λ₯Ό λ³΄κ΄€ν•˜κ³  κ΄€λ¦¬ν•©λ‹ˆλ‹€.

 

 

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

 

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

 

μ—”ν‹°ν‹°μ—λŠ” 4κ°€μ§€ μƒνƒœκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

 

  • λΉ„μ˜μ†(new/transient) : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ „ν˜€ 관계가 μ—†λŠ” μƒνƒœ
  • μ˜μ†(managed) : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μƒνƒœ (μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ κ΄€λ¦¬λœλ‹€λŠ” 뜻)
  • μ€€μ˜μ†(detached) : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯λ˜μ—ˆλ‹€κ°€ λΆ„λ¦¬λœ μƒνƒœ
  • μ‚­μ œ(removed) : μ‚­μ œλœ μƒνƒœ

 

 

🫧 λΉ„μ˜μ†

 

μ—”ν‹°ν‹° 객체λ₯Ό μƒμ„±ν•˜κ³  아직 μ €μž₯ν•˜μ§€ μ•Šμ•˜λ‹€λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ‚˜ λ°μ΄ν„°λ² μ΄μŠ€μ™€λŠ” μ „ν˜€ 관련이 μ—†λŠ” μƒνƒœμž…λ‹ˆλ‹€. 이것을 λΉ„μ˜μ† μƒνƒœλΌ ν•©λ‹ˆλ‹€.

 

// 객체λ₯Ό μƒμ„±ν•œ μƒνƒœ (λΉ„μ˜μ†)
User user = new User();
user.setId("user1");
user.setName("νšŒμ›1");

 

 

🫧 μ˜μ†

 

μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό ν†΅ν•΄μ„œ μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯ν•˜λ©΄, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜κ²Œ λ©λ‹ˆλ‹€. 이것을 μ˜μ† μƒνƒœλΌ ν•©λ‹ˆλ‹€. em.find() λ‚˜ JPQL 을 μ‚¬μš©ν•΄μ„œ μ‘°νšŒν•œ 엔티티도 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜λŠ” μ˜μ† μƒνƒœμž…λ‹ˆλ‹€.

 

// 객체λ₯Ό μ €μž₯ν•œ μƒνƒœ (μ˜μ†)
em.persist(user);

 

 

🫧 μ€€μ˜μ†

 

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜λ˜ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜μ§€ μ•ŠμœΌλ©΄ μ€€μ˜μ† μƒνƒœκ°€ λ©λ‹ˆλ‹€. em.detach(), em.close(), em.clear() λ₯Ό ν˜ΈμΆœν•˜λŠ” 경우 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜λ˜ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λŠ” μ€€μ˜μ† μƒνƒœκ°€ λ©λ‹ˆλ‹€.

 

// νšŒμ› μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 뢄리 (μ€€μ˜μ†)
em.detach(user);

 

 

🫧 μ‚­μ œ

 

μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‚­μ œν•œ μƒνƒœμž…λ‹ˆλ‹€.

 

// 객체λ₯Ό μ‚­μ œν•œ μƒνƒœ (μ‚­μ œ)
em.remove(user);

 

 

⭐️ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ‚¬μš©ν•˜λŠ” 이유

 

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜λ©΄ λ‹€μŒκ³Ό 같은 μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.

 

  • 1μ°¨ μΊμ‹œ
  • 동일성 보μž₯
  • νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜λŠ” μ“°κΈ° μ§€μ—°
  • λ³€κ²½ 감지
  • μ§€μ—° λ‘œλ”©

 

 

πŸ”₯ μ—”ν‹°ν‹° 쑰회

 

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” 내뢀에 μΊμ‹œλ₯Ό κ°€μ§€κ³  μžˆλŠ”λ°, 이λ₯Ό 1μ°¨ μΊμ‹œλΌ ν•©λ‹ˆλ‹€.

μ‰½κ²Œ μ–˜κΈ°ν•΄μ„œ μ˜μ†μ„± 내뢀에 Map 이 ν•˜λ‚˜ μžˆλŠ”λ°, ν‚€λŠ” @Id 둜 λ§€ν•‘ν•œ μ‹λ³„μžκ³  값은 μ—”ν‹°ν‹° μΈμŠ€ν„΄μŠ€μž…λ‹ˆλ‹€.

 

μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•  λ•Œ 1μ°¨ μΊμ‹œμ—μ„œ μ—”ν‹°ν‹°λ₯Ό μ°Ύκ³  λ§Œμ•½ 1μ°¨ μΊμ‹œμ— μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‘°νšŒν•©λ‹ˆλ‹€.

 

1μ°¨ μΊμ‹œμ—μ„œ 쑰회

 

1μ°¨ μΊμ‹œμ— μ—†μ–΄ λ°μ΄ν„°λ² μ΄μŠ€ 쑰회

 

1μ°¨ μΊμ‹œμ—μ„œ λ°”λ‘œ μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•  수 μžˆλŠ” 경우 μ„±λŠ₯상 이점을 λˆ„λ¦΄ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

 

πŸ”₯ μ—”ν‹°ν‹° 등둝

 

EntityManager λŠ” νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜κΈ° μ§μ „κΉŒμ§€ λ°μ΄ν„°λ² μ΄μŠ€μ— μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•˜μ§€ μ•Šκ³  λ‚΄λΆ€ 쿼리 μ €μž₯μ†Œμ— INSERT SQL 을 차곑차곑 λͺ¨μ•„λ‘‘λ‹ˆλ‹€. 그리고 νŠΈλžœμž­μ…˜μ„ 컀밋할 λ•Œ λͺ¨μ•„λ‘” 쿼리λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— λ³΄λ‚΄λŠ”λ° 이것을 νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜λŠ” μ“°κΈ° μ§€μ—° (transactional write-behind) 이라 ν•©λ‹ˆλ‹€.

 

μ“°κΈ° μ§€μ—°

 

컀밋

 

νŠΈλžœμž­μ…˜μ„ commit() ν•˜λ©΄ μ—”ν‹°ν‹° λ§€λ‹ˆμ €λŠ” μš°μ„  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό flush() ν•©λ‹ˆλ‹€. flush() λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½ λ‚΄μš©μ„ λ°μ΄ν„°λ² μ΄μŠ€μ— λ™κΈ°ν™”ν•˜λŠ” μž‘μ—…μΈλ° 이 λ•Œ 등둝, μˆ˜μ •, μ‚­μ œν•œ μ—”ν‹°ν‹°λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•©λ‹ˆλ‹€. ꡬ체적으둜 μ΄μ•ΌκΈ°ν•˜λ©΄ μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λͺ¨μΈ 쿼리λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— λ³΄λ‚Έλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.

 

 

πŸ”₯ λ³€κ²½ 감지

 

μ—”ν‹°ν‹°μ˜ 변경사항을 λ°μ΄ν„°λ² μ΄μŠ€μ— μžλ™μœΌλ‘œ λ°˜μ˜ν•˜λŠ” κΈ°λŠ₯을 λ³€κ²½ 감지 (dirty checking) 라고 ν•©λ‹ˆλ‹€.

 

λ³€κ²½ 감지

 

JPA λŠ” μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— 보관할 λ•Œ, 졜초 μƒνƒœλ₯Ό λ³΅μ‚¬ν•΄μ„œ μ €μž₯ν•΄λ‘λŠ”λ° 이것을 μŠ€λƒ…μƒ·μ΄λΌ ν•©λ‹ˆλ‹€.

그리고 flush() μ‹œμ μ— μŠ€λƒ…μƒ·κ³Ό μ—”ν‹°ν‹°λ₯Ό λΉ„κ΅ν•΄μ„œ λ³€κ²½λœ μ—”ν‹°ν‹°λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

 

  1. νŠΈλžœμž­μ…˜μ„ commit() ν•˜λ©΄ EntityManager λ‚΄λΆ€μ—μ„œ λ¨Όμ € flush() κ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€.
  1. 엔티티와 μŠ€λƒ…μƒ·μ„ λΉ„κ΅ν•΄μ„œ λ³€κ²½λœ μ—”ν‹°ν‹°λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.
  1. λ³€κ²½λœ μ—”ν‹°ν‹°κ°€ 있으면 μˆ˜μ • 쿼리λ₯Ό μƒμ„±ν•΄μ„œ μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ³΄λƒ…λ‹ˆλ‹€.
  1. μ“°κΈ° μ§€μ—° μ €μž₯μ†Œμ˜ SQL 을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ³΄λƒ…λ‹ˆλ‹€.
  1. λ°μ΄ν„°λ² μ΄μŠ€ νŠΈλžœμž­μ…˜μ„ commit() ν•©λ‹ˆλ‹€.

 

λ³€κ²½ κ°μ§€λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜λŠ” μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°μ—λ§Œ μ μš©λ©λ‹ˆλ‹€.

 

 

πŸ”₯ μ—”ν‹°ν‹° μ‚­μ œ

 

μ—”ν‹°ν‹°λ₯Ό μ‚­μ œν•˜λ©΄ μ—”ν‹°ν‹° 등둝과 λΉ„μŠ·ν•˜κ²Œ μ‚­μ œ 쿼리λ₯Ό μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ³΄κ΄€ν•©λ‹ˆλ‹€.

이후 νŠΈλžœμž­μ…˜μ„ commit() ν•΄μ„œ flush() λ₯Ό ν˜ΈμΆœν•˜λ©΄ μ‹€μ œ λ°μ΄ν„°λ² μ΄μŠ€μ— μ‚­μ œ 쿼리λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€.

단, em.remove() λ₯Ό ν˜ΈμΆœν•œ μˆœκ°„ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ μ‚­μ œλ©λ‹ˆλ‹€.

 

 

πŸ“š μ°Έκ³ 

 

μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ° - κΉ€μ˜ν•œ