πŸ“Œλͺ©μ°¨ 
 1. μ—”ν‹°ν‹° λ§€λ‹ˆμ € νŒ©ν† λ¦¬μ™€ μ—”ν‹°ν‹° λ§€λ‹ˆμ €
 2. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ—”ν‹°ν‹° 생λͺ…μ£ΌκΈ° 
 3. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ νŠΉμ§•

1. μ—”ν‹°ν‹° λ§€λ‹ˆμ € νŽ™ν† λ¦¬μ™€ μ—”ν‹°ν‹° λ§€λ‹ˆμ €

  • JPAμ—μ„œ Entity ManagerλŠ” Entity에 λŒ€ν•œ 쑰회, μˆ˜μ •, μ‚­μ œ, μ €μž₯ λ“± Entity와 κ΄€λ ¨λœ λͺ¨λ“  일을 μ²˜λ¦¬ν•©λ‹ˆλ‹€.
  • Entity Manager Factory λŠ” Entity Managerλ₯Ό μƒμ„±ν•˜λŠ” 역할을 ν•˜λ©° μƒμ„±ν•˜λŠ” λΉ„μš©μ΄ ν½λ‹ˆλ‹€.
  • 데이터 베이슀λ₯Ό ν•˜λ‚˜λ§Œ μ‚¬μš©ν•˜λŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” 일반적으둜 Entity Manager Factoryλ₯Ό ν•˜λ‚˜λ§Œ μƒμ„±ν•˜μ—¬ 이λ₯Ό κ³΅μœ ν•˜λ©° μ‚¬μš©ν•©λ‹ˆλ‹€.  
  • Entity Manager FactoryλŠ” Thread safe ν•©λ‹ˆλ‹€. ( μ„œλ‘œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— 접근해도 μ•ˆμ „ν•©λ‹ˆλ‹€. )
  • Entity Managerκ°€ ν•„μš”ν•  λ•Œλ§ˆλ‹€ Entity Manager Factory둜 μƒμ„±ν•˜λ©°, Thread safe ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    ( μ„œλ‘œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ λ™μ‹œ μ ‘κ·Όν•˜λ©΄ λ™μ‹œμ„± λ¬Έμ œκ°€ λ°œμƒ ) 

2. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ—”ν‹°ν‹° 생λͺ…μ£ΌκΈ°

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ( Persistence Context ) λž€ λ¬΄μ—‡μΌκΉŒμš”? 

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλž€ 'μ—”ν‹°ν‹°λ₯Ό 영ꡬ μ €μž₯ν•˜λŠ” ν™˜κ²½' μ΄λΌλŠ” λœ»μž…λ‹ˆλ‹€.
μ—”ν‹°ν‹° λ§€λ‹ˆμ €λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ—”ν‹°ν‹°λ₯Ό λ³΄κ΄€ν•˜κ³  κ΄€λ¦¬ν•©λ‹ˆλ‹€. 
논리적인 κ°œλ…μ— κ°€κΉŒμš°λ©° μ—¬λŸ¬ μ—”ν‹°ν‹° λ§€λ‹ˆμ €κ°€ 같은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Όν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 


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

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

2. μ˜μ† ( managed )           
3. μ€€μ˜μ† (detached )
4. μ‚­μ œ ( removed ) 

 

1. λΉ„μ˜μ† ( new / transient ) 
: μˆœμˆ˜ν•œ 객체 μƒνƒœ
둜 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ‘œ κ΄€λ¦¬λ˜κΈ° μ „μ˜ μƒνƒœ

Member member = new Member();	// μˆœμˆ˜ν•œ Java객체 생성
member.setName("홍길동");	// λ³€κ²½ κ°μ§€μ˜ λŒ€μƒμ΄ μ•„λ‹ˆλ©°, μ‹€μ œ DB의 엔티티와 λ¬΄κ΄€ν•œ μƒνƒœμž…λ‹ˆλ‹€.

2. μ˜μ† ( managed )

 : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ κ΄€λ¦¬λ˜λŠ” μƒνƒœμž…λ‹ˆλ‹€.

em.persist(member);	// μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— 객체λ₯Ό μ €μž₯ν•œ μƒνƒœ ( μ˜μ† )

* em.find () , JPQL의 쿼리 λ“±μœΌλ‘œ DBλ‘œλΆ€ν„° μ‘°νšŒν•œ μ—”티티도 λ§ˆμ°¬κ°€μ§€λ‘œ μ˜μ†μƒνƒœμž…λ‹ˆλ‹€.


3. μ€€μ˜μ† ( detached )
:
μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό 더이상 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜μ§€ μ•ŠλŠ” μƒνƒœ 

em.detach(member);	// 1.member μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ λΆ„λ¦¬ν•˜λŠ” λ©”μ„œλ“œ

# μ•„λž˜ 두가지 κ²½μš°μ—λ„ μ€€μ˜μ† μƒνƒœκ°€ λ©λ‹ˆλ‹€. 
em.close();	// μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό λ‹«λŠ” λ©”μ„œλ“œ
em.clear();	// μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” λ©”μ„œλ“œ

4.  μ‚­μ œ ( removed ) 
:
μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‚­μ œν•˜λŠ” 경우의 μƒνƒœ

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

3. μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ νŠΉμ§•

  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ‹λ³„μž κ°’  : μ—”ν‹°ν‹°λ₯Ό μ‹λ³„μž κ°’μœΌλ‘œ κ΅¬λΆ„ν•˜λ―€λ‘œ μ˜μ† μƒνƒœλŠ” λ°˜λ“œμ‹œ μ‹λ³„μž 값이 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. 
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ λ°μ΄ν„°λ² μ΄μŠ€ μ €μž₯ : μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯된 μ—”ν‹°ν‹°λŠ” νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜λŠ” μˆœκ°„ DB에 반영되며 이것을 Flush라고 ν•©λ‹ˆλ‹€.   
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜μ—¬ μƒκΈ°λŠ” 이점
    • 1μ°¨ μΊμ‹œ 
    • 동일성 보μž₯
    • νŠΈλžœμž­μ…˜μ„ μ§€μ›ν•˜λŠ”  μ“°κΈ° μ§€μ—°
    • λ³€κ²½ 감지
    • μ§€μ—° λ‘œλ”©

μ—”ν‹°ν‹° 쑰회

  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ 내뢀에 μΊμ‹œ( Map )κ°€ 있으며 이λ₯Ό 1μ°¨ μΊμ‹œλΌκ³  ν•©λ‹ˆλ‹€. ( λ©”λͺ¨λ¦¬μ— 쑴재 )
  • 1μ°¨ μΊμ‹œμ˜ Keyλ‘œλŠ” @Id둜 λ§€ν•‘ν•œ μ‹λ³„μžκ°€ μ‚¬μš©λ˜λ©° Value은 μ—”ν‹°ν‹° μΈμŠ€ν„΄μŠ€μž…λ‹ˆλ‹€.
  • μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λŠ” λͺ¨λ‘ 1μ°¨ μΊμ‹œμ— μ €μž₯λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•˜λŠ” 경우 λ¨Όμ € 1μ°¨ μΊμ‹œμ—μ„œ μ—”ν‹°ν‹°λ₯Ό μ°Ύκ³  λ§Œμ•½ 1μ°¨ μΊμ‹œμ— μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‘°νšŒν•˜μ—¬ μ—”ν‹°ν‹°λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 이후 1μ°¨ μΊμ‹œμ— μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•œ ν›„ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλŠ” μ‹λ³„μžλ₯Ό 톡해 1μ°¨ μΊμ‹œμ—μ„œ 같은 μ—”ν‹°ν‹° μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λ―€λ‘œ μ„±λŠ₯상 이점과 μ—”ν‹°ν‹°μ˜ 동일성을 보μž₯ν•©λ‹ˆλ‹€. ( μ•„λž˜ 경우 μ°Έκ³  ) 
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

System.out.println(a == b);	// 동일성 비ꡐ

κ²°κ³Ό : true

μ—”ν‹°ν‹° 등둝

  • μ—”ν‹°ν‹° λ§€λ‹ˆμ €λŠ” νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜κΈ° μ§μ „κΉŒμ§€ DB에 μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•˜μ§€ μ•Šκ³  μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— INSERT SQL을 λͺ¨μ•„두고 νŠΈλžœμž­μ…˜ 컀밋할 λ•Œ λͺ¨μ•„λ‘” 쿼리λ₯Ό DB에 λ³΄λƒ…λ‹ˆλ‹€. 이것을 μ“°κΈ° μ§€μ—°( Transactional write-behind )이라 ν•©λ‹ˆλ‹€.

μ—”ν‹°ν‹° μˆ˜μ •

  • μ—”ν‹°ν‹° μ‚­μ œ, 쑰회, μ €μž₯κ³ΌλŠ” λ‹€λ₯΄κ²Œ μ—”ν‹°ν‹°λ₯Ό μˆ˜μ •ν•˜λŠ” λ³„λ„μ˜ λ©”μ„œλ“œ( em.update() λ“± )λŠ” μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 
  • λ³€κ²½ 감지( Dirty Checking ) κΈ°λŠ₯을 ν†΅ν•˜μ—¬ μ—”ν‹°ν‹°μ˜ μˆ˜μ • 사항을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•©λ‹ˆλ‹€.
  • λ³€κ²½ κ°μ§€λž€ μ—”ν‹°ν‹°λ₯Ό μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— 보관할 λ•Œ ( μ €μž₯ λ˜λŠ” DBμ—μ„œ μ‘°νšŒν–ˆμ„ λ•Œ ), 졜초의 μƒνƒœλ₯Ό λ³΅μ‚¬ν•΄μ„œ μ €μž₯ν•΄λ‘‘λ‹ˆλ‹€. 이λ₯Ό μŠ€λƒ…μƒ·( Snap shot ) 이라 ν•˜λ©°, Flush μ‹œμ μ— μŠ€λƒ…μƒ·κ³Ό μ—”ν‹°ν‹°λ₯Ό λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ μ—”ν‹°ν‹°λ₯Ό μ°Ύκ³  λ³€κ²½λœ 엔티티에 λŒ€ν•œ μˆ˜μ • 쿼리λ₯Ό  μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ³΄λƒ…λ‹ˆλ‹€.
  • λ³€κ²½ κ°μ§€λŠ” μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°μ—λ§Œ μ μš©λ©λ‹ˆλ‹€.

JPA의 μ—…λ°μ΄νŠΈ μ „λž΅

  • JPAλŠ” 기본적으둜 μ—”ν‹°ν‹°μ˜ λͺ¨λ“  ν•„λ“œλ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” μ „λž΅μ„ μ‚¬μš©ν•˜λ©°, μ•„λž˜μ˜ 이점을 κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€. 
    • λͺ¨λ“  ν•„λ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μˆ˜μ • 쿼리가 항상 κ°™κ³ , λ”°λΌμ„œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‘œλ”© μ‹œμ μ— μˆ˜μ • 쿼리λ₯Ό 미리 생성해두고 μž¬μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • λ°μ΄ν„°λ² μ΄μŠ€μ— λ™μΌν•œ 쿼리λ₯Ό 보내면 λ°μ΄ν„°λ² μ΄μŠ€λŠ” 이전에 ν•œ 번 νŒŒμ‹±λœ 쿼리λ₯Ό μž¬μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.  
  • ν•„λ“œκ°€ λ§Žκ±°λ‚˜ μ €μž₯λ˜λŠ” λ‚΄μš©μ΄ λ„ˆλ¬΄ 큰 경우 μˆ˜μ •λœ λ°μ΄ν„°λ§Œ μ‚¬μš©ν•˜μ—¬ λ™μ μœΌλ‘œ UPDATE 쿼리λ₯Ό μƒμ„±ν•˜λŠ” μ „λž΅λ„ μ‘΄μž¬ν•©λ‹ˆλ‹€. 이 κ²½μš°μ—λŠ” Entity ν΄λž˜μŠ€μ— @DynamicUpdate μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.
@Entity
@DynamicUpdate		// λ™μ μœΌλ‘œ UPDATE SQL을 생성
public class Member{
	
    ...

}

μ—”ν‹°ν‹° μ‚­μ œ

  • μ—”ν‹°ν‹°λ₯Ό μ‚­μ œν•˜λ €λ©΄ μ‚­μ œ λŒ€μƒ μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • em.remove(member) μ‹œ member μ—”ν‹°ν‹° DELETE SQL을 μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ“±λ‘ν•©λ‹ˆλ‹€.
  • em.remove(member) λ₯Ό ν˜ΈμΆœν•˜λŠ” μˆœκ°„ member은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ μ œκ±°λ©λ‹ˆλ‹€.
Member member = em.find(Member.class , "member");	// μ‚­μ œ λŒ€μƒ μ—”ν‹°ν‹° 쑰회
em.remove(member);	// μ—”ν‹°ν‹° μ‚­μ œ : μ—”ν‹°ν‹° μ‚­μ œ SQL을 μ“°κΈ° μ§€μ—° μ €μž₯μ†Œλ‘œ 보내고, μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 제거

ν”ŒλŸ¬μ‹œ ( Flush )

  • ν”ŒλŸ¬μ‹œλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½ λ‚΄μš©μ„ λ°μ΄ν„°λ² μ΄μŠ€λ‘œ λ°˜μ˜ν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
  • ν”ŒλŸ¬μ‹œλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½ λ‚΄μš©μ„ λ°μ΄ν„°λ² μ΄μŠ€μ— λ™κΈ°ν™”ν•˜λŠ” 것이지 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— λ³΄κ΄€λœ μ—”ν‹°ν‹°λ₯Ό μ§€μš°λŠ” 것이 μ•„λ‹™λ‹ˆλ‹€. ( ν”ŒλŸ¬μ‹œλΌλŠ” 이름에 μ˜€ν•΄ν•˜μ§€ λ§™μ‹œλ‹€. )  
  • ν”ŒλŸ¬μ‹œλ₯Ό μ‹€ν–‰ν•˜λŠ” 경우 λ‹€μŒκ³Ό 같은 일이 μΌμ–΄λ‚©λ‹ˆλ‹€.
    1. λ³€κ²½ 감지가 λ™μž‘ν•΄μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μžˆλŠ” λͺ¨λ“  μ—”ν‹°ν‹°λ₯Ό μŠ€λƒ…μƒ·κ³Ό λΉ„κ΅ν•΄μ„œ μˆ˜μ •λœ μ—”ν‹°ν‹°λ₯Ό μ°ΎλŠ”λ‹€.
      μˆ˜μ •λœ μ—”ν‹°ν‹°λŠ” μˆ˜μ • 쿼리λ₯Ό λ§Œλ“€μ–΄ μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ— λ“±λ‘ν•œλ‹€.
    2. μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†Œμ˜ 쿼리λ₯Ό λ°μ΄ν„°λ² μ΄μŠ€μ— μ „μ†‘ν•œλ‹€. ( 등둝, μˆ˜μ •, μ‚­μ œ 쿼리

ν”ŒλŸ¬μ‹œλ₯Ό ν˜ΈμΆœν•˜λŠ” 방법 3κ°€μ§€

  • 직접  호좜
    μ—”ν‹°ν‹° λ§€λ‹ˆμ €μ˜ flush() λ₯Ό 직접 ν˜ΈμΆœν•˜μ—¬ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό κ°•μ œλ‘œ ν”ŒλŸ¬μ‹œν•œλ‹€. ν…ŒμŠ€νŠΈλ‚˜ λ‹€λ₯Έ ν”„λ ˆμž„μ›Œν¬μ™€ JPAλ₯Ό ν•¨κ»˜ μ‚¬μš©ν•  λ•Œλ₯Ό μ œμ™Έν•˜κ³  거의 μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • νŠΈλžœμž­μ…˜ 컀밋 μ‹œ ν”ŒλŸ¬μ‹œ μžλ™ 호좜
    λ°μ΄ν„°λ² μ΄μŠ€
    의 λ³€κ²½ λ‚΄μš©μ„  SQL둜 μ „λ‹¬ν•˜μ§€ μ•Šκ³  νŠΈλžœμž­μ…˜λ§Œ μ»€λ°‹ν•˜λ©΄ μ–΄λ–€ 데이터도 λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ νŠΈλžœμž­μ…˜μ„ μ»€λ°‹ν•˜κΈ° 전에 κΌ­ ν”ŒλŸ¬μ‹œλ₯Ό ν˜ΈμΆœν•΄μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€κ²½ λ‚΄μš©μ„ λ°μ΄ν„°λ² μ΄μŠ€μ— λ°˜μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€. JPAλŠ” 이런 문제λ₯Ό μ˜ˆλ°©ν•˜κΈ° μœ„ν•΄ νŠΈλžœμž­μ…˜μ„ 컀밋할 λ•Œ ν”ŒλŸ¬μ‹œλ₯Ό μžλ™μœΌλ‘œ ν˜ΈμΆœν•©λ‹ˆλ‹€.
  • JPQL 쿼리 μ‹€ν–‰ μ‹œ ν”ŒλŸ¬μ‹œ μžλ™ 호좜
    JPQL
    μ΄λ‚˜ Criteria 같은 객체지ν–₯ 쿼리λ₯Ό ν˜ΈμΆœν•  λ•Œλ„ ν”ŒλŸ¬μ‹œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€. ( SQL둜 λ³€ν™˜λ˜μ–΄ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό 쑰회 ) 
  • μ‹λ³„μžλ₯Ό κΈ°μ€€μœΌλ‘œ μ‘°νšŒν•˜λŠ” find()의 κ²½μš°μ—λŠ” ν”ŒλŸ¬μ‹œκ°€ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

// JPAμ—μ„œ 쀑간에 JPQL둜 μ‘°νšŒν•˜λŠ” 경우 DB에 memberA, memberB, memberC κ°€ λ°˜μ˜λ˜μ§€ μ•Šμ•„ 
// 쿼리 결과둜 μ‘°νšŒλ˜μ§€ μ•ŠλŠ” 것듀을 μ˜ˆλ°©ν•˜κΈ° μœ„ν•˜μ—¬ ν”ŒλŸ¬μ‹œλ₯Ό μžλ™μœΌλ‘œ ν˜ΈμΆœν•¨ 
query = em.createQuery("SELECT m FROM Member m", Member.class);
List<Member> members = query.getResultList();

ν”ŒλŸ¬μ‹œ λͺ¨λ“œ μ˜΅μ…˜

  • FlushModeType.AUTO : μ»€λ°‹μ΄λ‚˜ 쿼리λ₯Ό μ‹€ν–‰ν•  λ•Œ ν”ŒλŸ¬μ‹œ ( κΈ°λ³Έκ°’ )
  • FlushModeType.COMMIT : 컀밋할 λ•Œλ§Œ ν”ŒλŸ¬μ‹œ
  • COMMIT λͺ¨λ“œλŠ” μ„±λŠ₯ μ΅œμ ν™”λ₯Ό μœ„ν•΄ μ‚¬μš©ν•  수 μžˆλ‹€κ³  ν•©λ‹ˆλ‹€.
em.setFlushMode(FlushModeType.COMMIT) // ν”ŒλŸ¬μ‹œ λͺ¨λ“œλ₯Ό 직접 μ„€μ •

μ€€μ˜μ†

  • μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ λΆ„λ¦¬λœ( detached ) 것을 μ€€μ˜μ† μƒνƒœλΌ ν•©λ‹ˆλ‹€. λ”°λΌμ„œ μ€€μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯을 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • 크게 3κ°€μ§€ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό μ€€μ˜μ† μƒνƒœλ‘œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. detach() / clear() / close() 

μ—”ν‹°ν‹°λ₯Ό μ€€μ˜μ† μƒνƒœλ‘œ μ „ν™˜ : detach( entity )

  • νŠΉμ • μ—”ν‹°ν‹°λ§Œ μ€€μ˜μ† μƒνƒœλ‘œ λ§Œλ“œλŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€. 
  • 이 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” μˆœκ°„ 1μ°¨ μΊμ‹œλΆ€ν„° μ“°κΈ° μ§€μ—° SQL μ €μž₯μ†ŒκΉŒμ§€ ν•΄λ‹Ή μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜κΈ° μœ„ν•œ λͺ¨λ“  정보가 μ œκ±°λ©λ‹ˆλ‹€.
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ 더이상 κ΄€λ¦¬ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ νŠΈλžœμž­μ…˜μ„ 컀밋해도 λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
# detach() λ©”μ„œλ“œ μ •μ˜
public void detach(Object entity);

# μ‚¬μš© μ˜ˆμ‹œ
em.persist(member);	// member μ—”ν‹°ν‹° μ˜μ† μƒνƒœ
...				
em.detach(member)	// μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 뢄리, member μ—”ν‹°ν‹° μ€€μ˜μ† μƒνƒœ

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ΄ˆκΈ°ν™” : clear( )

  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ΄ˆκΈ°ν™”ν•΄μ„œ ν•΄λ‹Ή μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λͺ¨λ“  μ—”ν‹°ν‹°λ₯Ό μ€€μ˜μ† μƒνƒœλ‘œ λ§Œλ“œλŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€
    .( μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ œκ±°ν•˜κ³  μƒˆλ‘œ λ§Œλ“œλŠ” 것과 같은 효과 )
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λ‹€μŒ μ½”λ“œμ˜ setUsername()에 λŒ€ν•œ λ³€κ²½ 감지가 λ™μž‘ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
// μ—”ν‹°ν‹° 쑰회, μ˜μ† μƒνƒœκ°€ 됨
Member member = em.find(Member.class, "memberA");

em.clear();	// μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ΄ˆκΈ°ν™”

// μ€€μ˜μ† μƒνƒœ
member.setUsername("changeName");

μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ’…λ£Œ : close( )

  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ’…λ£Œμ‹œν‚€λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ’…λ£Œν•˜λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ κ΄€λ¦¬ν•˜λ˜ λͺ¨λ“  μ—”ν‹°ν‹°κ°€ μ€€μ˜μ† μƒνƒœκ°€ λ©λ‹ˆλ‹€.
μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λŠ” 주둜 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ’…λ£Œλ˜λ©΄μ„œ μ€€μ˜μ† μƒνƒœκ°€ λ©λ‹ˆλ‹€. κ°œλ°œμžκ°€ 직접 μ€€μ˜μ† μƒνƒœλ‘œ λ§Œλ“œλŠ” 일은 λ“œλ¬Όλ‹€κ³  ν•©λ‹ˆλ‹€. 

μ€€μ˜μ† μƒνƒœμ˜ νŠΉμ§•

  • 거의 λΉ„μ˜μ† μƒνƒœμ— κ°€κΉμŠ΅λ‹ˆλ‹€.
    ( 1μ°¨ μΊμ‹œ, μ“°κΈ° μ§€μ—°, λ³€κ²½ 감지, μ§€μ—° λ‘œλ”©μ„ ν¬ν•¨ν•œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ œκ³΅ν•˜λŠ” μ–΄λ–€ κΈ°λŠ₯도 λ™μž‘ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ) 
  • μ‹λ³„μž 값을 κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€.
    ( λΉ„μ˜μ† μƒνƒœλŠ” μ‹λ³„μž 값이 없을 수 μžˆμ§€λ§Œ μ€€μ˜μ† μƒνƒœλŠ” 이미 ν•œ 번 μ˜μ† μƒνƒœμ˜€μœΌλ―€λ‘œ λ°˜λ“œμ‹œ μ‹λ³„μž 값을 κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€. κΈ°λ³Έν‚€ 생성 μ „λž΅μ„ IDENTITY둜 μ‚¬μš©ν•˜λŠ” 경우 persist() μ‹œ DB에 μ ‘κ·Ό )
  • μ§€μ—° λ‘œλ”©μ„ ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

병합 : merge( entity )

  • μ€€μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό λ‹€μ‹œ μ˜μ† μƒνƒœλ‘œ λ³€κ²½ν•˜λ €λ©΄ 병합을 μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.
  • merge() λ©”μ„œλ“œλŠ” μ€€μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό λ°›μ•„ κ·Έ μ •λ³΄λ‘œ μƒˆλ‘œμš΄ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
  • νŒŒλΌλ―Έν„°λ‘œ μ‚¬μš©λœ μ—”ν‹°ν‹°λŠ” merge()이후에도 μ€€μ˜μ† μƒνƒœλ‘œ λ‚¨μ•„μžˆμŠ΅λ‹ˆλ‹€.
public class ExamMergeMain{
	
    public static void main(String[] args){
    
    	Member member = createMember("memberA", "νšŒμ›1");
        
        member.setUsername("νšŒμ›λͺ…λ³€κ²½");	// μ€€μ˜μ† μƒνƒœμ—μ„œ λ³€κ²½
        
        mergeMember(member);
    }
	
    static Member createMember(String id, String userName){
    	// μ˜μ†μ„± μ»¨νƒμŠ€νŠΈ 1 μ‹œμž‘ 
        EntityManager em1 = emf.createEntityManager();
        EntityTransaction tx1 = em1.getTransaction();
        tx1.begin();
        
        Member member = new Member();
        member.setId(id);
        member.setUserName(userName);
        
        em1.persist(member);
        tx1.commit();	// member μ—”ν‹°ν‹°κ°€ db에 반영됨
      
        em1.close();	// μ˜μ†μ„± μ»¨νƒμŠ€νŠΈ 1 μ’…λ£Œ, member μ—”ν‹°ν‹°κ°€ μ€€μ˜μ† μƒνƒœκ°€ 됨
        
        return member;
    }

	static void mergeMember(Member member){
    	// μ˜μ†μ„± μ»¨νƒμŠ€νŠΈ 2 μ‹œμž‘
        EntityManager em2 = emf.createEntityManager();
        EntityTransaction tx2 = em2.getTransaction();
        
        tx2.begin();
        em2.merge(member);	// μ€€μ˜μ† μƒνƒœμ˜ member에 merge() μˆ˜ν–‰ 
        tx2.commit();

	// μ€€μ˜μ† μƒνƒœ
        System.out.println("member = " + member.getUsername());

        // μ˜μ† μƒνƒœ
        System.out.println("mergeMember = " + mergeMember.getUsername());
        System.out.println("em2 contains member = " + em2.contains(member));
        System.out.println("em2 contains mergeMember = " + em2.contains(mergeMember));
        
        em2.close();	// μ˜μ†μ„± μ»¨νƒμŠ€νŠΈ 2 μ’…λ£Œ
    }

}


# 좜λ ₯ κ²°κ³Ό
member = νšŒμ›λͺ…λ³€κ²½
mergeMember = νšŒμ›λͺ…λ³€κ²½
em2 contains member = false
em2 contains mergeMember = true

 

  • main λ©”μ„œλ“œμ—μ„œ setUserName()을 ν˜ΈμΆœν•˜μ˜€μ§€λ§Œ 이미 em1이 μ’…λ£Œλœ μƒνƒœμ΄λ―€λ‘œ member은 μ€€μ˜μ† μƒνƒœμ΄κ³ , λ³€κ²½ 감지가 μΌμ–΄λ‚˜μ§€ λͺ»ν•˜λŠ” μƒν™©μž…λ‹ˆλ‹€.
  • mergeMember()λ©”μ„œλ“œμ—μ„œ member의 μ‹λ³„μžλ₯Ό 기반으둜 ν•œ μƒˆλ‘œμš΄ μ˜μ† μƒνƒœμ˜ μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•˜κ³ , 이 κ³Όμ •μ—μ„œ λ³€κ²½ 감지가 λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€. 
  • containsλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜λŠ”μ§€ ν™•μΈν•˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€.
    ( 좜λ ₯ κ²°κ³Ό member은 em2에 κ΄€λ¦¬λ˜κ³  μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 즉, μ—¬μ „νžˆ μ€€μ˜μ† μƒνƒœμ΄λ©° μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ˜€λ‹€λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. ) 

이제 merge( )의 λ™μž‘ 과정을 ꡬ체적으둜 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€. 

  1. merge( )λ₯Ό μ‹€ν–‰ν•œλ‹€.
  2. νŒŒλΌλ―Έν„°λ‘œ λ„˜μ–΄μ˜¨ μ€€μ˜μ† μ—”ν‹°ν‹°μ˜ μ‹λ³„μž κ°’μœΌλ‘œ 1μ°¨ μΊμ‹œμ—μ„œ μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•œλ‹€.
    • λ§Œμ•½ 1μ°¨ μΊμ‹œμ— μ—”ν‹°ν‹°κ°€ μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•˜κ³  1μ°¨ μΊμ‹œμ— μ €μž₯ν•œλ‹€. 
      ( 이 κ³Όμ •μ—μ„œ 1μ°¨ μΊμ‹œμ— snapshot이 μ €μž₯되고, 이후 λ³€κ²½ 감지가 μˆ˜ν–‰λ˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. ) 
  3. μ‘°νšŒν•œ μ˜μ† μ—”ν‹°ν‹°( mergeMember )에 member μ—”ν‹°ν‹°μ˜ 값을 μ±„μ›Œ λ„£λŠ”λ‹€. 
    ( member μ—”ν‹°ν‹°μ˜ λͺ¨λ“  값을 mergeMember에 λ°€μ–΄ λ„£λŠ”λ‹€. μ΄λ•Œ mergeMember의 "νšŒμ›1"μ΄λΌλŠ” 이름이 "νšŒμ›λͺ…λ³€κ²½"으둜 바뀐닀. )
  4. mergeMemberλ₯Ό λ°˜ν™˜ν•œλ‹€.

λΉ„μ˜μ† 병합

  • merge( )λŠ” λΉ„μ˜μ† 엔티티도 μ˜μ† μƒνƒœλ‘œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. 
  • νŒŒλΌλ―Έν„°λ‘œ λ„˜μ–΄μ˜¨ μ—”ν‹°ν‹°μ˜ μ‹λ³„μž κ°’μœΌλ‘œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ‘°νšŒν•˜κ³  μ°ΎλŠ” μ—”ν‹°ν‹°κ°€ μ—†μœΌλ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ‘°νšŒν•©λ‹ˆλ‹€. ( db에도 μ—†μœΌλ©΄ μƒˆλ‘œμš΄ μ—”ν‹°ν‹°λ₯Ό μƒμ„±ν•΄μ„œ λ³‘ν•©ν•©λ‹ˆλ‹€. )
μ •λ¦¬ν•˜μžλ©΄ 병합은 μ‹λ³„μž κ°’μœΌλ‘œ μ—”ν‹°ν‹°λ₯Ό μ‘°νšŒν•  수 있으면 λΆˆλŸ¬μ„œ λ³‘ν•©ν•˜κ³  μ‘°νšŒν•  수 μ—†μœΌλ©΄ μƒˆλ‘œ μƒμ„±ν•΄μ„œ λ³‘ν•©ν•©λ‹ˆλ‹€. 즉, save or update κΈ°λŠ₯을 μˆ˜ν–‰ν•©λ‹ˆλ‹€. 

# 글에 μ‚¬μš©λœ μ„€λͺ…κ³Ό μ½”λ“œλŠ” κΉ€μ˜ν•œλ‹˜μ˜ "μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ°"을 μ •λ¦¬ν•œ λ‚΄μš©μž…λ‹ˆλ‹€.

'JPA' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[ JPA ] κΈ°λ³Έ ν‚€ λ§€ν•‘  (2) 2023.08.05

+ Recent posts