πŸ”Ž Overview

Β @OneToMany λ“±μ˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•  λ•Œ, CascadeType 을 μ„€μ •ν•˜λŠ” 것을 자주 λ³΄μ•˜μ„ 것이닀.

Β  기본적으둜 1:N μ΄μƒμ˜ 연관관계일 λ•Œ, 연관관계에 μžˆλŠ” ν•œ μ—”ν‹°ν‹° ν•„λ“œμ˜ λ³€ν™”κ°€ λ‹€λ₯Έ μ—”ν‹°ν‹° ν•„λ“œμ— 영ν–₯을 μ£Όμ§€ μ•ŠλŠ”λ‹€.

Β  예λ₯Ό λ“€μ–΄, κΈ€κ³Ό λŒ“κΈ€μ€ μ„œλ‘œ 1:N 연관관계이닀.
이 경우, 1번 글에 λŒ“κΈ€μ„ μ—¬λŸ¬ 개 μž‘μ„±ν•˜κ³  1번 글을 μ‚­μ œν•˜λ €κ³  ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. μ΄λŠ” λŒ“κΈ€λ“€μ΄ 1번 글에 λŒ€ν•œ μ™Έλž˜ν‚€λ₯Ό κ°€μ§€κ³  있기 λ•Œλ¬Έμ΄λ‹€.

Β  Cascadeλ₯Ό ν™œμš©ν•˜λ©΄, 1:1이 μ•„λ‹Œ λ‹€μ–‘ν•œ κ΄€κ³„μ—μ„œλ„ ν•œ μ—”ν‹°ν‹°μ˜ 변화에 λ”°λ₯Έ λ‹€λ₯Έ μ—”ν‹°ν‹°μ˜ λ³€ν™”λ₯Ό 섀정해쀄 수 μžˆλ‹€.


πŸ“• Cascade

  • λΆ€λͺ¨ 엔티티와 μžμ‹ μ—”ν‹°ν‹° κ°„μ˜ μƒνƒœ 전이λ₯Ό μžλ™ν™”ν•˜λŠ” κΈ°λŠ₯
  • JPA μ—μ„œ μ—”ν‹°ν‹° κ°„μ˜ μ—°κ΄€ 관계λ₯Ό λ‹€λ£° λ•Œ μ‚¬μš©
  • λΆ€λͺ¨ μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•˜κ±°λ‚˜ μ‚­μ œν•  λ•Œ, μžμ‹ 엔티티도 섀정에 따라 μ €μž₯ ν˜Ήμ€ μ‚­μ œλ˜λ„λ‘ μ²˜λ¦¬ν•  수 있음

πŸ“‘ CascadeType의 μ’…λ₯˜

1) CascadeType.ALL

  • λͺ¨λ“  CascadeType 을 ν—ˆκ°€
  • λΆ€λͺ¨ μ—”ν‹°ν‹°μ˜ λͺ¨λ“  μƒνƒœ 전이λ₯Ό μžμ‹ 엔티티에 μ „νŒŒ
@OneToMany(mappedBy = "question", cascade = CascadeType.All)	// μ—°κ΄€ κ΄€κ³„μ˜ 주인은 question λ³€μˆ˜λ‘œ μ €μž₯된 ν•„λ“œ, λͺ¨λ“  μƒνƒœ 전이 ν—ˆκ°€
private List<Answer> answerList;

2) CascadeType.PERSIST

  • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯될 λ•Œ, μžμ‹ 엔티티도 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯
@OneToMany(mappedBy = "question", cascade = CascadeType.PERSIST		// λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ EntityMangerλ₯Ό 톡해 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— persist ν•˜λ©΄, μžμ‹ 엔티티도 ν•¨κ»˜ persist
private List<Answer> answerList;

Question question = new Question();
Answer answer = new Answer();
question.addAnswer(answer);		// μ›λž˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯λ˜μ§€ μ•ŠμŒ

entityManager.persist(question);	// DB에 μ €μž₯

3) CascadeType.MERGE

  • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 병합될 λ•Œ, μžμ‹ 엔티티도 ν•¨κ»˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 병합
@OneToMany(mappedBy = "question", cascade = CascadeType.MERGE
private List<Answer> answerList;

Question question = entityManager.find(Question.class, 1L)	// 이 μ‹œμ μ— μ˜μ†ν™”
question.setContent("new content");

Answer answer = new Answer();	// λΉ„μ˜μ† 객체
answer.setContent("answer content");
question.addAnswer(answer);

entityManager.merge(question);	// λΆ€λͺ¨, μžμ‹ μ—”ν‹°ν‹° λͺ¨λ‘ 병합

4) CascadeType.REMOVE

  • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ‚­μ œλ  λ•Œ, μžμ‹ 엔티티도 ν•¨κ»˜ μ‚­μ œ
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE
private List<Answer> answerList;

Question question = entityManager.find(Question.class, 1L)
entityManger.remove(question);	// λΆ€λͺ¨, μžμ‹ μ—”ν‹°ν‹° λͺ¨λ‘ μ‚­μ œ

5) CascadeType.REFRESH

  • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μƒˆλ‘œ 고침되면 μžμ‹ 엔티티도 μƒˆλ‘œ κ³ μΉ¨
@OneToMany(mappedBy = "question", cascade = CascadeType.REFRESH)
private List<Answer> answerList;

6) CascadeType.DETACH

  • λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ λΆ„λ¦¬λ˜λ©΄, μžμ‹ 엔티티도 ν•¨κ»˜ 뢄리
  • DETACH λŠ” μ—”ν‹°ν‹°λ₯Ό μ€€μ˜μ†ν™” μ‹œν‚€λŠ” κ²ƒμœΌλ‘œ, entityManger.detach λ‚˜ @Transcational μž‘μ—… 이후에 μ μš©λœλ‹€.

  • Cascade 의 경우 기본값이 μ—†λ‹€. 즉, μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ©΄ λΉ„ν™œμ„± μƒνƒœμ΄λ‹€.

πŸ•› CascadeλŠ” μ–Έμ œ μ“°λŠ” 게 μ’‹μ„κΉŒ?

1) λΆ€λͺ¨-μžμ‹ κ΄€κ³„μ˜ 데이터가 항상 ν•¨κ»˜ κ΄€λ¦¬λ˜μ–΄μ•Ό ν•  λ•Œ

  • 글이 μ‚­μ œλ˜λ©΄ λŒ“κΈ€μ€ λͺ¨λ‘ ν•¨κ»˜ μ‚­μ œλ˜μ–΄μ•Ό 함
  • νšŒμ› νƒˆν‡΄λ₯Ό ν•˜λ©΄ νšŒμ›μ˜ μž₯λ°”κ΅¬λ‹ˆ λͺ©λ‘μ€ λͺ¨λ‘ μ‚­μ œλ˜μ–΄μ•Ό 함

2) μ½”λ“œμ˜ κ°„κ²°μ„±κ³Ό μœ μ§€λ³΄μˆ˜μ„±μ„ 높일 λ•Œ

  • Cascade λ₯Ό μ‚¬μš©ν•˜λ©΄ λΆ€λͺ¨ μ—”ν‹°ν‹°λ§Œ 관리해도 μžμ‹ μ—”ν‹°ν‹°μ˜ 생λͺ…μ£ΌκΈ°λ₯Ό μžλ™μœΌλ‘œ μ²˜λ¦¬ν•  수 있음
  • 이λ₯Ό 톡해 μ½”λ“œκ°€ λ”μš± λ‹¨μˆœν™”

3) λ§Žμ§€ μ•Šμ€ 데이터λ₯Ό λ‹€λ£° λ•Œ

  • λ§Žμ€ μžμ‹ μ—”ν‹°ν‹°κ°€ μ—°κ΄€λœ 경우, Cascade 둜 인해 μ„±λŠ₯ λ¬Έμ œκ°€ λ°œμƒν•  수 있음
  • μ΄λŸ¬ν•œ 경우 λ³„λ„μ˜ Repository 등을 μ΄μš©ν•΄μ„œ 관리

↔️ Cascade의 μž₯단점

1) μž₯점

  • μžλ™ν™”
    • λΆ€λͺ¨ μ—”ν‹°ν‹°λ§Œ μž‘μ—…ν•΄λ„ μžμ‹ μ—”ν‹°ν‹°μ—μ„œ μžλ™μœΌλ‘œ μ²˜λ¦¬λ˜λ―€λ‘œ, μ½”λ“œκ°€ λ‹¨μˆœν•΄μ§
  • μ½”λ“œ μž¬μ‚¬μš©μ„± 증가
    • λΆ€λͺ¨ μ—”ν‹°ν‹°λ§Œ μž‘μ—…ν•΄λ„ λ˜λ―€λ‘œ, 쀑볡 μ½”λ“œμ˜ μž‘μ„± κ°μ†Œ
  • 관계 관리 용이
    • μ™Έλž˜ν‚€ 등을 μ‹ κ²½ μ“Έ ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ—, μ—°κ΄€ κ΄€κ³„μ˜ 데이터 관리가 쉬움

2) 단점

  • μ„±λŠ₯ μ €ν•˜
    • μ „νŒŒλ₯Ό ν•¨λΆ€λ‘œ μ“°λ©΄ λΆˆν•„μš”ν•œ 쿼리가 λŠ˜μ–΄μ„œ μ„±λŠ₯의 μ €ν•˜λ₯Ό 초래
  • 섀계 μ˜μ‘΄μ„± 증가
    • 잘λͺ»λœ μ„€μ •μœΌλ‘œ μΈν•œ μ˜λ„μΉ˜ μ•Šμ€ 데이터 손싀 λ°œμƒ κ°€λŠ₯
  • λ³΅μž‘ν•œ 디버깅
    • Cascade 둜 μΈν•œ μ—λŸ¬λŠ” 디버깅을 톡해 μΆ”μ ν•˜κΈ° μ–΄λ €μšΈ 수 있음

‼️Cascade와 κ΄€λ ¨λœ μ€‘μš”ν•œ λ‚΄μš©

  • ν•΄λ‹Ή λ‚΄μš©μ€ ν•„μžκ°€ λŠλΌκΈ°μ— 정말 맀우맀우 ν—·κ°ˆλ¦¬κ³  μ€‘μš”ν•œ λ‚΄μš©
  • 반볡적인 ν•™μŠ΅μ„ 톡해 ν™•μ‹€νžˆ μ•Œκ³  κ°€μž

🀝 Cascade와 DB, 그리고 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ

  • Cascade <-> μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ
    • μ„œλ‘œκ°„μ˜ 직접적인 영ν–₯
    • cascadeλ₯Ό ν†΅ν•œ λ³€ν™”λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 객체에 영ν–₯을 쀌
  • Cascade <-> λ°μ΄ν„°λ² μ΄μŠ€
    • μ„œλ‘œκ°„μ˜ 간접적인 영ν–₯
    • persist 에 μ˜ν•΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ λ³€ν™”κ°€ λ°œμƒν•˜λ”λΌλ„, νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ rollback 이 μˆ˜ν–‰λ˜λ©΄ DB 의 λ°μ΄ν„°λŠ” λ³€ν•˜μ§€ μ•ŠμŒ

βœ”οΈ @Transcationalκ³Ό Cascade

  • @Transactional 의 경우, 맨 λ§ˆμ§€λ§‰ commit 될 λ•Œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ λ‚΄μ˜ 엔티티듀이 μžλ™μœΌλ‘œ flush λ˜μ–΄ DB 에 μ €μž₯
  • 즉, cascade μ˜΅μ…˜μœΌλ‘œ μ§€μ •λœ ν•„λ“œμ˜ λ³€ν™”κ°€ 생기더라도 commit μ΄μ „μ—λŠ” DB λ°μ΄ν„°μ˜ λ³€ν™”κ°€ μ—†μŒ


⭐ 연관관계와 CascadeType.PERSIST

  • CascadeType.PERSIST λŠ” λΆ€λͺ¨ 엔티티와 μžμ‹ μ—”ν‹°ν‹° 사이 연관관계가 μ‘΄μž¬ν•  λ•Œ μž‘λ™
  • 연관관계가 μ—†μœΌλ©΄ μžμ‹ 객체듀을 μžλ™μœΌλ‘œ μ˜μ†ν™” ν•˜μ§€ μ•ŠμŒ
  • CascadeType.PERSIST κ°€ μ„€μ •λœ 경우, λΆ€λͺ¨ μ—”ν‹°ν‹°κ°€ μ˜μ†ν™” ν•˜λŠ” μ‹œμ μ— μžμ‹ 엔티티도 μžλ™μœΌλ‘œ μ˜μ†ν™”

βœ’οΈ 배운 λ‚΄μš©μœΌλ‘œ 정리

❕CascadeType.PERSIST 적용 μƒνƒœ

@Transactional
public void doMethod() {
	Question question = new Question();	// ν˜„μž¬ λΉ„μ˜μ† μƒνƒœ
	Answer answer1 = new Answer();		// ν˜„μž¬ λΉ„μ˜μ† μƒνƒœ
	Answer answer2 = new Answer();		// ν˜„μž¬ λΉ„μ˜μ† μƒνƒœ

	// addAnswer λ©”μ„œλ“œλŠ” 쿼리둜 μ—°κ²°λ˜μ§€ μ•Šμ€, λ‹¨μˆœνžˆ λ©”λͺ¨λ¦¬μƒμ˜ List에 Answer 객체λ₯Ό λ”ν•˜λŠ” μž‘μ—…
	question.addAnswer(answer1);	// 아직 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯ X
	question.addAnswer(answer2);	// 아직 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ €μž₯ X
    
    // νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ μ— μ˜μ†ν™” κ²°μ •
}
  • νŠΈλžœμž­μ…˜μ˜ 컀밋 μ΄μ „μ—λŠ” λͺ¨λ“  객체가 μ „λΆ€ λ‹€ λΉ„μ˜μ† μƒνƒœ

  • νŠΈλžœμž­μ…˜ 컀밋 μ‹œμ 

  1. persist κ°€ μ μš©λ˜μ§€ μ•Šμ•˜κ³ , Question κ³Ό Answer κ°€ 연관관계가 아닐 λ•Œ
    • question κ³Ό answer1 , answer2 λͺ¨λ‘ μ˜μ†ν™” λ˜μ§€ μ•ŠμŒ

  2. persist κ°€ μ μš©λ˜μ§€ μ•Šμ•˜κ³ , Question κ³Ό Answer λŠ” 연관관계이며, Answer κ°€ μ—°κ΄€κ΄€κ³„μ˜ 주인일 λ•Œ
    • question 은 μ˜μ†ν™”λ˜μ§€λ§Œ, answer1 κ³Ό answer2 λŠ” μ˜μ†ν™”λ˜μ§€ μ•ŠμŒ
    • 연관관계일 경우, λΆ€λͺ¨ μ—”ν‹°ν‹°λŠ” μ˜μ†ν™”

  3. persist κ°€ 적용되고, Question κ³Ό Answer κ°€ 연관관계가 아닐 λ•Œ
    • question 은 μ˜μ†ν™”λ˜μ§€λ§Œ, answer1 κ³Ό answer2 λŠ” μ˜μ†ν™”λ˜μ§€ μ•ŠμŒ
    • persist κ°€ 적용된 λΆ€λͺ¨ μ—”ν‹°ν‹°λŠ” μ˜μ†ν™”

  4. persist κ°€ 적용되고, Question κ³Ό Answer κ°€ 연관관계일 λ•Œ
    • question, answer1 , answer2 κ°€ λͺ¨λ‘ μ˜μ†ν™”
  • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— λ“±λ‘λœ λͺ¨λ“  λ³€κ²½ 사항이 DB 에 반영


πŸ”š λ§ˆλ¬΄λ¦¬μ§€μœΌλ©°..

Β  κ³΅λΆ€ν•˜λ©° 정리λ₯Ό ν•˜λ‹€λ³΄λ‹ˆ ν—·κ°ˆλ¦¬κ³  λͺ¨λ₯΄λŠ” 뢀뢄이 λ„ˆλ¬΄ λ§Žμ•˜λ‹€.

 특히 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ™€ μ˜μ†ν™”, μ€€μ˜μ†ν™” λ“±μ˜ κ°œλ…μ— λŒ€ν•΄ 계속 ν˜Όλ™μ΄ μ™€μ„œ ν•˜λ£¨μ’…μΌ μ°Ύμ•„λ³Έ 것 κ°™λ‹€.
μ—°κ΄€λœ λ‚΄μš©μ΄ λ§Žλ‹€λ³΄λ‹ˆ λ‚΄κ°€ μ§€κΈˆ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ •λ¦¬ν•˜λŠ” 건지, cascadeλ₯Ό μ •λ¦¬ν•˜λŠ”κ±΄μ§€ λͺ¨λ₯΄κ² λ‹€..
배운 λ‚΄μš©μ„ μžŠμ–΄λ²„λ¦¬κΈ° 전에, λΉ λ₯Έ μ‹œμΌ 내에 ν•™μŠ΅ν•œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— κ΄€ν•œ λ‚΄μš©μ„ λΈ”λ‘œκ·Έμ— μ •λ¦¬ν•˜λ„λ‘ ν•΄μ•Όκ² λ‹€.

Β πŸ˜΅β€πŸ’« 이 ν•œ 번의 ν¬μŠ€νŒ… 정리λ₯Ό μœ„ν•΄ μ§ˆλ¬Έν•΄κ°€λ©° ν•™μŠ΅ν•œ λ‚΄μš©μ˜ 슀크둀..


μ°Έκ³ ) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/

profile
기둝

0개의 λŒ“κΈ€