TIL/Spring

πŸ“š 3/13(수) 내일배움캠프 Java-Spring 54일차 TIL - SpringData JPA μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ

zzu_dev 2024. 3. 14. 17:03

πŸ“  μ˜€λŠ˜μ˜ ν•™μŠ΅ ν‚€μ›Œλ“œ 

  • SpringData JPA - μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ

 

 

 

 

 

 

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

  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ(Persistence Context)λŠ” JPA(Java Persistence API)μ—μ„œ 핡심적인 κ°œλ… 쀑 ν•˜λ‚˜λ‘œ, μ—”ν‹°ν‹°(Entity) 객체λ₯Ό κ΄€λ¦¬ν•˜λŠ” ν™˜κ²½μ„ 의λ―Έν•œλ‹€. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ—”ν‹°ν‹°μ˜ μƒνƒœλ₯Ό μΆ”μ ν•˜κ³  κ΄€λ¦¬ν•˜μ—¬ λ°μ΄ν„°λ² μ΄μŠ€μ™€μ˜ μƒν˜Έμž‘μš©μ„ λ‹΄λ‹Ήν•œλ‹€. μ—”ν‹°ν‹°λ₯Ό 영ꡬ μ €μž₯ν•˜λŠ” ν™˜κ²½μœΌλ‘œ μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό 톡해 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Όν•œλ‹€.

 

πŸ“ μ—”ν‹°ν‹°(Entity)λž€? 
 μ—”ν‹°ν‹°λž€ λ°μ΄ν„°λ² μ΄μŠ€μ˜ ν…Œμ΄λΈ”μ— λŒ€μ‘ν•˜λŠ” 클래슀라고 μƒκ°ν•˜λ©΄ λœλ‹€. @Entityκ°€ 뢙은 ν΄λž˜μŠ€λŠ” JPAμ—μ„œ κ΄€λ¦¬ν•˜λ©° 이λ₯Ό 엔티티라고 ν•œλ‹€. 클래슀 μžμ²΄λ‚˜ μƒμ„±ν•œ μΈμŠ€ν„΄μŠ€λ„ 엔티티라고 λΆ€λ₯Έλ‹€.

πŸ“ μ—”ν‹°ν‹° λ§€λ‹ˆμ €(Entity Manager)λž€? 
    μ—”ν‹°ν‹° λ§€λ‹ˆμ €λž€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Όν•˜μ—¬ 엔티티에 λŒ€ν•œ λ°μ΄ν„°λ² μ΄μŠ€ μž‘μ—…μ„ μ œκ³΅ν•œλ‹€. λ‚΄λΆ€μ μœΌλ‘œ λ°μ΄ν„°λ² μ΄μŠ€ 컀λ„₯μ…˜μ„ μ‚¬μš©ν•΄μ„œ λ°μ΄ν„°λ² μ΄μŠ€μ— μ ‘κ·Όν•œλ‹€.

πŸ“ μ˜μ†μ„±μ΄λž€? 
  λ°μ΄ν„°λ₯Ό μƒμ„±ν•œ ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜μ–΄λ„ 사라지지 μ•ŠλŠ” λ°μ΄ν„°μ˜ νŠΉμ„±μ„ λ§ν•œλ‹€. μ˜μ†μ„±μ„ κ°–μ§€ μ•ŠμœΌλ©΄ λ°μ΄ν„°λŠ” λ©”λͺ¨λ¦¬μ—μ„œλ§Œ μ‘΄μž¬ν•˜κ²Œ 되고 ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜λ©΄ ν•΄λ‹Ή λ°μ΄ν„°λŠ” λͺ¨λ‘ μ‚¬λΌμ§€κ²Œ λœλ‹€. κ·Έλž˜μ„œ μš°λ¦¬λŠ” 데이터λ₯Ό νŒŒμΌμ΄λ‚˜ DB에 영ꡬ μ €μž₯ν•¨μœΌλ‘œμ¨ 데이터에 μ˜μ†μ„±μ„ λΆ€μ—¬ν•œλ‹€.

 

 

 

 

 

 

πŸ“ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ νŠΉμ§• 

  • μ—”ν‹°ν‹° 관리 : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ—”ν‹°ν‹° 객체λ₯Ό 관리ν•œλ‹€. μ—”ν‹°ν‹° 객체λ₯Ό μƒμ„±ν•˜κ³ , μ‘°νšŒν•˜κ³ , μˆ˜μ •ν•˜κ³ , μ‚­μ œν•˜λŠ” μž‘μ—…μ„ 톡해 μ—”ν‹°ν‹°μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό μΆ”μ ν•˜κ³ , μ—”ν‹°ν‹°μ˜ μƒνƒœλ₯Ό κ΄€λ¦¬ν•œλ‹€.
  • 엔티티와 λ°μ΄ν„°λ² μ΄μŠ€ κ°„μ˜ λ§€ν•‘ : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” 엔티티와 λ°μ΄ν„°λ² μ΄μŠ€ ν…Œμ΄λΈ” κ°„μ˜ 맀핑을 λ‹΄λ‹Ήν•œλ‹€. μ—”ν‹°ν‹° 객체의 μƒνƒœ 변경이 λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜λ˜λ„λ‘ μ μ ˆν•œ SQL 쿼리λ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν•œλ‹€.
  • 동일성 보μž₯ : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ—”ν‹°ν‹° 객체의 동일성을 보μž₯ν•œλ‹€. 같은 μ—”ν‹°ν‹° μ‹λ³„μž(primary key)λ₯Ό κ°€μ§„ μ—”ν‹°ν‹° κ°μ²΄λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ‚΄μ—μ„œ λ™μΌν•œ μΈμŠ€ν„΄μŠ€λ‘œ κ΄€λ¦¬λœλ‹€. 1μ°¨ μΊμ‹œμ— μ €μž₯된 μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•˜κΈ° λ•Œλ¬Έμ— ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μ—μ„œ 같은 ν‚€κ°’μœΌλ‘œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μ—”ν‹°ν‹° 쑰회 μ‹œ, 같은 μ—”ν‹°ν‹° 쑰회λ₯Ό 보μž₯ν•œλ‹€. 
  • νŠΈλžœμž­μ…˜ λ²”μœ„ : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” νŠΈλžœμž­μ…˜ λ²”μœ„ λ‚΄μ—μ„œ λ™μž‘ν•œλ‹€. 즉, νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•˜κ³  μ’…λ£Œν•  λ•ŒκΉŒμ§€ μ—”ν‹°ν‹°μ˜ 변경을 μΆ”μ ν•˜κ³  κ΄€λ¦¬ν•©λ‹ˆλ‹€. νŠΈλžœμž­μ…˜μ΄ μ’…λ£Œλ˜λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°μ˜ 변경을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•œλ‹€.
  • μ§€μ—° λ‘œλ”© : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ§€μ—° λ‘œλ”©(Lazy Loading)을 μ§€μ›ν•œλ‹€. μ—°κ΄€λœ μ—”ν‹°ν‹°λ₯Ό μ‹€μ œλ‘œ μ‚¬μš©ν•  λ•ŒκΉŒμ§€ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 데이터λ₯Ό λ‘œλ“œν•˜μ§€ μ•Šκ³ , ν•„μš”ν•  λ•Œ λ‘œλ”©μ„ μˆ˜ν–‰ν•œλ‹€.
  • μΊμ‹œ : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μΌμ’…μ˜ μΊμ‹œ 역할을 ν•œλ‹€. 1μ°¨ μΊμ‹œκ°€ μ‘΄μž¬ν•˜λ©° Map<KEY, VALUE>둜 μ €μž₯λœλ‹€. 이미 λ‘œλ“œλœ μ—”ν‹°ν‹°λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ 내에 μΊμ‹±λ˜μ–΄ μž¬μ‚¬μš©λ  수 있으며, entityManager.find() λ©”μ†Œλ“œ 호좜 μ‹œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 1μ°¨ μΊμ‹œλ₯Ό μ‘°νšŒν•œλ‹€. μ‘°νšŒν•œ μ—”ν‹°ν‹°κ°€ μ‘΄μž¬ν•  경우 ν•΄λ‹Ή μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•˜κ³ , μ—”ν‹°ν‹°κ°€ μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 쑰회 ν›„ 1μ°¨ μΊμ‹œμ— μ €μž₯ 및 λ°˜ν™˜ν•œλ‹€.

 

 

 

 

 

 

 

πŸ“ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ‚¬μš©μ‹œ 이점

  μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό λ°μ΄ν„°λ² μ΄μŠ€ 사이에 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλΌλŠ” 쀑간 계측이 있으면 버퍼링, 캐싱 등을 ν•  수 μžˆλ‹€λŠ” μž₯점이 μžˆλ‹€. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ νŠΉμ§•μ— λ”°λ₯Έ 이점을 μ•Œμ•„λ³΄μž.

 

 

  • 1μ°¨μΊμ‹œ

  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—λŠ” 1μ°¨ μΊμ‹œκ°€ μ‘΄μž¬ν•˜λ©° Map<key, value="">둜 μ €μž₯λœλ‹€. e</key,>ntityManager.find() λ©”μ†Œλ“œ 호좜 μ‹œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 1μ°¨ μΊμ‹œλ₯Ό μ‘°νšŒν•œλ‹€. μ‘°νšŒν•œ μ—”ν‹°ν‹°κ°€ μ‘΄μž¬ν•  경우 ν•΄λ‹Ή μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•˜κ³ , μ—”ν‹°ν‹°κ°€ μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 쑰회 ν›„ 1μ°¨ μΊμ‹œμ— μ €μž₯ 및 λ°˜ν™˜ν•œλ‹€.

<μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ 1μ°¨ μΊμ‹œ ꡬ쑰 - 좜처: μŠ€ν”„λ§ λΆ€νŠΈ μ‡Όν•‘λͺ° ν”„λ‘œμ νŠΈ with JPA>

 

 

  • 동일성 보μž₯

ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μ—μ„œ 같은 ν‚€κ°’μœΌλ‘œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μ—”ν‹°ν‹° 쑰회 μ‹œ, 같은 μ—”ν‹°ν‹° 쑰회λ₯Ό 보μž₯ν•œλ‹€. 1μ°¨ μΊμ‹œμ— μ €μž₯된 μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•˜κΈ° λ•Œλ¬Έμ— 동일성 보μž₯이 κ°€λŠ₯ν•˜λ‹€.

 

 

 

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

  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—λŠ” μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œκ°€ μ‘΄μž¬ν•œλ‹€. entityManager.persist()λ₯Ό ν˜ΈμΆœν•˜λ©΄ 1μ°¨ μΊμ‹œμ— μ €μž₯λ˜λŠ” 것과 λ™μ‹œμ— μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— SQL문이 μ €μž₯λœλ‹€. μ΄λ ‡κ²Œ SQL을 μŒ“μ•„λ‘κ³  νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜λŠ” μ‹œμ μ— μ €μž₯된 SQL문듀이 flushλ˜λ©΄μ„œ λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜λœλ‹€. μ΄λ ‡κ²Œ λͺ¨μ•„μ„œ 보내기 λ•Œλ¬Έμ— μ„±λŠ₯μ—μ„œλ„ 이점을 λ³Ό 수 μžˆλ‹€.

<μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œ - 좜처: μŠ€ν”„λ§ λΆ€νŠΈ μ‡Όν•‘λͺ° ν”„λ‘œμ νŠΈ with JPA>

 

 

  • λ³€κ²½ 감지

  JPAλŠ” 1μ°¨ μΊμ‹œμ— λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 처음 뢈러온 μ—”ν‹°ν‹°μ˜ μŠ€λƒ…μƒ· 값을 κ°–κ³  μžˆλ‹€. 그리고 1μ°¨ μΊμ‹œμ— μ €μž₯된 엔티티와 μŠ€λƒ…μƒ·μ„ 비ꡐ ν›„ λ³€κ²½ λ‚΄μš©μ΄ μžˆλ‹€λ©΄ UPDATE SQL문을 μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ‹΄μ•„λ‘”λ‹€. 그리고 λ°μ΄ν„°λ² μ΄μŠ€μ— 컀밋 μ‹œμ μ— λ³€κ²½ λ‚΄μš©μ„ μžλ™μœΌλ‘œ λ°˜μ˜ν•œλ‹€. 즉, λ”°λ‘œ update문을 ν˜ΈμΆœν•  ν•„μš”κ°€ μ—†λ‹€.

 

 

 

 

 

 

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

  μ—”ν‹°ν‹° 생λͺ…μ£ΌκΈ°μ˜ μ’…λ₯˜λ‘œλŠ” λ„€κ°€μ§€κ°€ μžˆλ‹€.

 

<μ—”ν‹°ν‹° 생λͺ…μ£ΌκΈ° - 좜처: μŠ€ν”„λ§ λΆ€νŠΈ μ‡Όν•‘λͺ° ν”„λ‘œμ νŠΈ with JPA>

 

  • λΉ„μ˜μ†(new/transient) - μ—”ν‹°ν‹° 객체가 λ§Œλ“€μ–΄μ Έμ„œ 아직 μ €μž₯λ˜μ§€ μ•Šμ€ μƒνƒœλ‘œ, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ „ν˜€ 관계가 μ—†λŠ” μƒνƒœ
  • μ˜μ†(managed) - μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯λ˜μ–΄, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ 관리할 수 μžˆλŠ” μƒνƒœ                                                                                 μ˜μ† μƒνƒœμ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯λ˜μ§€ μ•ŠμœΌλ©°, νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ— λ°μ΄ν„°λ² μ΄μŠ€μ— 반영
  • μ€€μ˜μ†(detached) - μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯λ˜μ–΄ μžˆλ‹€κ°€ λΆ„λ¦¬λœ μƒνƒœλ‘œ, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ 더 이상 κ΄€λ¦¬ν•˜μ§€ μ•ŠλŠ” μƒνƒœ
  • μ‚­μ œ(removed) - μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‚­μ œν•˜κ² λ‹€κ³  ν‘œμ‹œν•œ μƒνƒœ

 

 

 

 

 

 

πŸ“ λ™μž‘확인해보기

  μƒν’ˆ μ—”ν‹°ν‹°λ₯Ό λ§Œλ“€μ–΄μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯ ν›„, λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•΄λ³΄μž.

Item item = new Item();		// 1
item.setItemNm("ν…ŒμŠ€νŠΈ μƒν’ˆ");	

EntityManager em = entityManagerFactory.createEntityManager();	// 2

EntityTransaction transaction = em.getTransaction();		// 3
transaction.begin();		

em.persist(item);		// 4-1
em.flush(item).     // 4-2 (DB에 SQL 보내기/commitμ‹œ μžλ™μˆ˜ν–‰λ˜μ–΄ μƒλž΅ κ°€λŠ₯함)

transaction.commit();		// 5

em.close();			// 6


1️⃣  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— 담을 μƒν’ˆ μ—”ν‹°ν‹° 생성
2️⃣  μ—”ν‹°ν‹° λ§€λ‹ˆμ € νŒ©ν† λ¦¬λ‘œλΆ€ν„° μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό 생성
3️⃣  데이터 λ³€κ²½ μ‹œ 무결성을 μœ„ν•΄ νŠΈλžœμž­μ…˜ μ‹œμž‘
4️⃣  μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μƒνƒœ, 아직 DB에 INSERT SQL 보내기 μ „
5️⃣  νŠΈλžœμž­μ…˜μ„ DB에 반영, 이 λ•Œ μ‹€μ œλ‘œ INSERT SQL 컀밋 μˆ˜ν–‰
6️⃣  μ—”ν‹°ν‹° λ§€λ‹ˆμ €μ™€ μ—”ν‹°ν‹° λ§€λ‹ˆμ € νŒ©ν† λ¦¬ μžμ›μ„ close() 호좜둜 λ°˜ν™˜