λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Spring/JPA

[JPA] orphanRemoval μ˜΅μ…˜μ„ μ‚¬μš©ν•  λ•Œ Update μ£Όμ˜μ‚¬ν•­

by ν‘μ‹œλ°” 2023. 10. 28.

πŸ˜‚  λ°°κ²½

ν”„λ‘œμ νŠΈ 개발 쀑 νŠΉμ • 엔티티에 10κ°œκ°€ λ„˜λŠ” ν•„λ“œλ₯Ό μ—…λ°μ΄νŠΈλ₯Ό ν•΄λ‹¬λΌλŠ” λΉ„μ¦ˆλ‹ˆμŠ€ μš”κ΅¬μ‚¬ν•­μ΄ μžˆμ—ˆλ‹€.

κ·Έλž˜μ„œ 10κ°œκ°€ λ„˜λŠ” ν•„λ“œλ₯Ό 각각 μ—…λ°μ΄νŠΈν•˜λŠ” λ©”μ„œλ“œλ₯Ό μž‘μ„±ν–ˆλŠ”λ°.. 보기에 λ³„λ‘œ μ’‹μ•„ 보이지 μ•Šμ•˜λ‹€.

 

ν•„μžλŠ” JPA의 save() λ©”μ„œλ“œκ°€ 톡해 μ €μž₯κ³Ό 변경에 λŒ€ν•œ κΈ°λŠ₯을 ν•œ λ²ˆμ— μ œκ³΅ν•˜κ³  μžˆλ‹€λŠ” κ±Έ μ•Œκ³  μžˆμ—ˆλ‹€. κ·Έλž˜μ„œ λΉŒλ” νŒ¨ν„΄μœΌλ‘œ κΈ°μ‘΄ ID, κ°’, λ³€κ²½λœ 값을 μΆ”κ°€ν•œ  μƒˆλ‘œμš΄ μ—”ν‹°ν‹°λ₯Ό λ§Œλ“€μ–΄μ„œ save()λ₯Ό 톡해 μ—…λ°μ΄νŠΈν•˜λŠ” 게 보기에도 μ’‹κ³  효율적으둜 λ³΄μ˜€λ‹€. μƒκ°λŒ€λ‘œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ³  ν…ŒμŠ€νŠΈ ν•œ λ’€ λ‚˜λ¦„ 결과에 λ§Œμ‘±ν–ˆλ‹€.

 

그러던 μ–΄λŠ λ‚  운영 νŒ€μ—μ„œ 연락이 μ˜¨λ‹€.

 

"μ—…λ°μ΄νŠΈλ₯Ό ν–ˆλ”λ‹ˆ μ—°κ²°λœ 데이터가 λ‹€ μ‚¬λΌμ‘ŒλŠ”λ°μš”?"

 "????"

 

운영 쀑에 ν΄λΌμ΄μ–ΈνŠΈκ°€ μ—…λ°μ΄νŠΈλ₯Ό ν–ˆλŠ”λ°, 데이터가 λ‹€ μ‚¬λΌμ‘Œλ‹€κ³  ν•œλ‹€. 무슨 일인가 μ‹Άμ–΄μ„œ μ„œλ‘˜λŸ¬ μ½”λ“œλ₯Ό ν™•μΈν–ˆλ‹€.

원인

μ—…λ°μ΄νŠΈ μ½”λ“œ μž‘μ„± 이후 λ‚˜μ€‘μ— μΆ”κ°€λœ 연관관계에 orphanRemoval=trueκ°€ λ˜μ–΄μžˆλ˜ 게 λ¬Έμ œμ˜€λ‹€.

 

λ‹€λ₯Έ κ°œλ°œμžκ°€ ν•΄λ‹Ή μ—”ν‹°ν‹°μ—λŠ” orphanRemoval μ˜΅μ…˜κ³Ό ν•¨κ»˜ μ—°κ΄€ 관계λ₯Ό μΆ”κ°€ν–ˆλŠ”λ°, 막상 κΈ°μ‘΄ μ—…λ°μ΄νŠΈ λ‘œμ§μ€ μˆ˜μ •ν•˜μ§€ μ•Šμ•˜λ‹€. κ·Έλž˜μ„œ 이후에 μ—…λ°μ΄νŠΈ APIλ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ ν•΄λ‹Ή μ—°κ΄€ 관계 ν•„λ“œμ—λŠ” null 값이 λ“€μ–΄κ°€κ²Œ 되고, κ²°κ΅­ orphanRemoval μ˜΅μ…˜μ— μ˜ν•΄ μ‚­μ œκ°€ λ˜μ–΄λ²„λ¦° 것이닀.

ν•΄κ²°

문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법은 μ—…λ°μ΄νŠΈ λΉŒλ”μ— ν•΄λ‹Ή 연관관계λ₯Ό μΆ”κ°€ν•΄μ„œ μˆ˜μ •ν•˜κ±°λ‚˜ update λ©”μ„œλ“œλ₯Ό λ‹€μ‹œ μ—΄μ‹¬νžˆ λ§Œλ“œλŠ” 방식 2κ°€μ§€μ˜€λ‹€.

 

ν•„μžλŠ” ν›„μžλ₯Ό μ„ νƒν–ˆλ‹€. 같은 λ¬Έμ œκ°€ λ°œμƒν•˜μ§€ μ•ŠμœΌλ¦¬λΌλŠ” 보μž₯이 μ—†μ—ˆκΈ° λ•Œλ¬Έμ΄λ‹€.

마무리

λ‹€ν–‰νžˆ DBλŠ” 백업이 되고 μžˆμ—ˆκΈ° λ•Œλ¬Έμ— λŒ€λΆ€λΆ„μ˜ 데이터λ₯Ό λ³΅κ΅¬ν•˜λŠ” 데 μ„±κ³΅ν–ˆλ‹€.

μ‚¬λΌμ‘Œλ˜ 데이터가 κ·Έλ ‡κ²Œ μ€‘μš”ν•œ 데이터가 μ•„λ‹ˆμ—ˆκ³ , 볡ꡬ가 κ°€λŠ₯ν–ˆκΈ° λ•Œλ¬Έμ— λ‹€ν–‰μ΄μ—ˆλ‹€.

 

덕뢄에 DB λ°±μ—…μ˜ μ€‘μš”μ„±μ— λŒ€ν•΄ λ‹€μ‹œ ν•œλ²ˆ μƒκ°ν•˜κ²Œ λ˜μ—ˆκ³ , 이후 λ™μΌν•œ μš”κ΅¬μ‚¬ν•­μ΄ μžˆμ„ λ•Œ 더 이상 save()λ₯Ό μ΄μš©ν•œ μ—…λ°μ΄νŠΈ λ‘œμ§μ„ μž‘μ„±ν•˜μ§€ μ•Šκ³  Dirty Checking을 ν™œμš©ν•œ update λ©”μ„œλ“œλ₯Ό μƒμ„±ν•΄μ„œ λ‘œμ§μ„ μž‘μ„±ν•˜κ²Œ λ˜μ—ˆλ‹€.

 

 

[ ν¬μŠ€νŒ… κ΄€λ ¨ μ•Œλ©΄ 쒋은 지식 ]

 

1. orphanRemoval νŠΉμ§•

 

orphanRemoval μ˜΅μ…˜μ„ true둜 ν•˜λ©΄ κΈ°μ‘΄ NULL처리된 μžμ‹μ„ μ‚­μ œ μ²˜λ¦¬ν•œλ‹€.

PK(JoinColumn) 값이 NULL둜 λ³€ν•œ μžμ‹μ€ 고아객체. 즉, μ—°κ²°λœ 점이 μ—†λŠ” 객체이닀. 

orphanRemoval μ˜΅μ…˜μ€ μ΄λŸ¬ν•œ 고아객체λ₯Ό μ‚­μ œν•˜λŠ” 역할을 ν•œλ‹€.

 

2. JPA update

 

JPAλŠ” saveλ©”μ„œλ“œλ₯Ό 톡해 μ €μž₯κ³Ό 변경에 λŒ€ν•œ κΈ°λŠ₯을 ν•œ λ²ˆμ— μ œκ³΅ν•œλ‹€.

 

JPAλŠ” Dirty Checking을 톡해 μ˜μ†ν™”λœ μ—”ν‹°ν‹°λ“€μ˜ 변경을 μžλ™μœΌλ‘œ κ°μ§€ν•΄μ„œ μˆ˜μ • 쿼리λ₯Ό DB에 μ „λ‹¬ν•œλ‹€.
μ˜μ†ν™”λœ μ—”ν‹°ν‹°λŠ” saveλ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ JPA에 μ˜ν•΄ λ³€κ²½ 사항이 μžλ™μœΌλ‘œ DB에 μ μš©λœλ‹€.

+ Reference

https://tecoble.techcourse.co.kr/post/2021-08-15-jpa-cascadetype-remove-vs-orphanremoval-true/

 

JPA CascadeType.REMOVE vs orphanRemoval = true

JPAλ₯Ό κ³΅λΆ€ν•˜λ‹€ 보면 λ°”λ‘œ μ΄ν•΄ν•˜κΈ° 쉽지 μ•Šμ€ κ°œλ…λ“€μ„ λͺ‡ 개 λ§ˆμ£ΌμΉœλ‹€. ν•„μžλŠ” 연관관계 맀핑, μ˜μ†μ„± 전이, κ³ μ•„ 객체 등이 특히 μ–΄λ €μ› λ‹€. μ΄λ•Œ 와 κ°€ μœ λ… ν—·κ°ˆλ ΈλŠ”λ°, 직접 ν•™μŠ΅ ν…ŒμŠ€νŠΈλ₯Ό μž‘

tecoble.techcourse.co.kr

 

λŒ“κΈ€