๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“– Java & Spring & Kotlin/๐ŸŒฑ Spring

[ Spring ] CascadeType.REMOVE์™€ orphanRemoval=true, ์ž˜๋ชป ์“ฐ๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ ์•„๊ฐ‘๋‹ˆ๋‹ค!!

by carrot0911 2025. 1. 17.

๊ณต๋ถ€ํ•˜๊ฒŒ ๋œ ๊ณ„๊ธฐ

๊ฐ•์˜๋ฅผ ๋“ฃ๋‹ค๊ฐ€ Cascade์™€ orphanRemoval์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ๋‚˜์™”๋‹ค. ์ฒ˜์Œ์—๋Š” "์•„~ ์ด๋Ÿฐ ๊ฑฐ๊ตฌ๋‚˜" ํ•˜๊ณ  ๋ฌด์‹ฌ์ฝ” ๋„˜์–ด๊ฐ€๋ ค ํ–ˆ์ง€๋งŒ, ๊ฐ•์˜๊ฐ€ ์ง„ํ–‰๋ ์ˆ˜๋ก ๋จธ๋ฆฟ์†์— ๋ฌผ์Œํ‘œ๊ฐ€ ๊ฐ€๋“ ์ฐจ๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค.
"Cascade๊ฐ€ ๋ญ์ง€? ์ด๊ฑธ ์–ธ์ œ ์จ์•ผ ํ•˜์ง€?", "orphanRemoval์€ ๋˜ ๋ญ”๋ฐ...?๋ผ๋Š” ์ƒ๊ฐ์ด ๊ผฌ๋ฆฌ์— ๊ผฌ๋ฆฌ๋ฅผ ๋ฌผ์—ˆ๋‹ค.
๊ฒฐ๊ตญ, ๊ฐ•์˜๋ฅผ ๋“ฃ๋Š” ๋‚ด๋‚ด ์ •ํ™•ํžˆ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ฑ„๋กœ ๋ฉํ•˜๋‹ˆ ์ง€๋‚˜๊ฐ€๊ณ  ๋ง์•˜๋‹ค.
"์ด๋Œ€๋กœ ๋„˜์–ด๊ฐ€๋ฉด ๋‚˜์ค‘์— ๋˜ ๋ง‰ํž ๊ฑฐ์•ผ"๋ผ๋Š” ์ƒ๊ฐ์ด ๋จธ๋ฆฌ๋ฅผ ์Šค์ณค๊ณ , ์ด๋ ‡๊ฒŒ ๋œ ๊น€์— ๊ฐœ๋…์„ ์ œ๋Œ€๋กœ ์ •๋ฆฌํ•ด๋ณด์ž๋Š” ๋งˆ์Œ์œผ๋กœ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
Cascade์™€ orphanRemoval์€ JPA์—์„œ ๊ฝค ์ค‘์š”ํ•œ ๊ฐœ๋…์ด์ง€๋งŒ, ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉด์„œ ๋Š๋‚€ ๊ฑด "๋ง์€ ์‰ฌ์›Œ ๋ณด์ด๋Š”๋ฐ, ๋ง‰์ƒ ์ดํ•ดํ•˜๋ ค๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ๋ณต์žกํ•˜๋‹ค"๋Š” ๊ฑฐ์˜€๋‹ค. ์ด๊ฑธ ์ œ๋Œ€๋กœ ์•Œ๊ณ  ๊ฐ€์•ผ ์•ž์œผ๋กœ JPA๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ๋œ ํ—ค๋งฌ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•˜๋‹ค.
๊ทธ๋ž˜์„œ ๋‹ค์–‘ํ•œ ์ž๋ฃŒ๋ฅผ ์ฐพ์•„๋ณด๊ณ , ์ฝ”๋“œ๋„ ์‚ดํŽด๋ณด๋ฉด์„œ ์ฐจ๊ทผ์ฐจ๊ทผ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค.


Cascade

๋ถ€๋ชจ Entity๊ฐ€ ์˜์†ํ™”๋  ๋•Œ ์ž์‹ Entity๋„ ๊ฐ™์ด ์˜์†ํ™”๋˜๊ณ , ๋ถ€๋ชจ Entity๊ฐ€ ์‚ญ์ œ๋  ๋•Œ ์ž์‹ Entity๋„ ์‚ญ์ œ๋˜๋Š” ๋“ฑ ํŠน์ • Entity๋ฅผ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค ๋•Œ ์—ฐ๊ด€๋œ Entity๋„ ํ•จ๊ป˜ ์˜์† ์ƒํƒœ๋กœ ์ „์ด๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
ํŠน์ • Entity์— ๋Œ€ํ•ด ํŠน์ •ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ๊ด€๋ จ๋œ Entity์—๋„ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.


Type

JPA์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์—ฐ๊ด€๋œ Entity ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด Enum ํƒ€์ž…์˜ CascadeType์„ ์ œ๊ณตํ•œ๋‹ค.

CascadeType.ALL : ๋ชจ๋“  Cascade๋ฅผ ์ ์šฉํ•œ๋‹ค.

  • ์ƒ์œ„ Entity์—์„œ ํ•˜์œ„ Entity๋กœ ๋ชจ๋“  ์ž‘์—…์„ ์ „ํŒŒํ•œ๋‹ค.
@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
    private List<Address> addresses;
}
@Entity
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String street;
    private int houseNumber;
    private String city;
    private int zipCode;

    @ManyToOne(fetch = FetchType.LAZY)
    private Person person;
}

CascadeType.PPERSIST : Entity๋ฅผ ์˜์†ํ™”ํ•  ๋•Œ, ์—ฐ๊ด€๋œ Entity๋„ ํ•จ๊ป˜ ์œ ์ง€ํ•œ๋‹ค.

  • ํ•˜์œ„ Entity๊นŒ์ง€ ์˜์†์„ฑ์„ ์ „๋‹ฌํ•œ๋‹ค.

CascadeType.MERGE : Entity ์ƒํƒœ๋ฅผ ๋ณ‘ํ•ฉํ•  ๋•Œ, ์—ฐ๊ด€๋œ Entity๋„ ๋ชจ๋‘ ๋ณ‘ํ•ฉํ•œ๋‹ค.

  • ํ•˜์œ„ Entity๊นŒ์ง€ ๋ณ‘ํ•ฉ ์ž‘์—…์„ ์ง€์†ํ•œ๋‹ค.

CascadeType.REMOVE : Entity๋ฅผ ์ œ๊ฑฐํ•  ๋•Œ, ์—ฐ๊ด€๋œ Entity๋„ ๋ชจ๋‘ ์ œ๊ฑฐํ•œ๋‹ค.

  • ํ•˜์œ„ Entity๊นŒ์ง€ ์ œ๊ฑฐ ์ž‘์—…์„ ์ง€์†ํ•œ๋‹ค.

CascadeType.REFRESH : ๋ถ€๋ชจ Entity๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจํ•  ๋•Œ, ์—ฐ๊ด€๋œ Entity๋„ ๋ชจ๋‘ ์ƒˆ๋กœ๊ณ ์นจ๋œ๋‹ค.

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ๋ถ€ํ„ฐ ์ธ์Šคํ„ด์Šค ๊ฐ’์„ ๋‹ค์‹œ ์ฝ์–ด ์˜จ๋‹ค. (์ƒˆ๋กœ ๊ณ ์นจ)
  • ์—ฐ๊ฒฐ๋œ ํ•˜์œ„ Entity๊นŒ์ง€ ์ธ์Šคํ„ด์Šค ๊ฐ’์„ ์ƒˆ๋กœ ๊ณ ์นจํ•œ๋‹ค.

CascadeType.DETACH : ๋ถ€๋ชจ Entity๋ฅผ DETACH ์ˆ˜ํ–‰ํ•˜๋ฉด, ์—ฐ๊ด€ Entity๋„ DETACH ์ƒํƒœ๊ฐ€ ๋˜์–ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ Entity๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
  • ์—ฐ๊ฒฐ๋œ ํ•˜์œ„ Entity๊นŒ์ง€ ์˜์†์„ฑ์„ ์ œ๊ฑฐํ•œ๋‹ค.

CascadeType.REMOVE์™€ orphanRemoval=true์˜ ์ฐจ์ด์ 

CascadeType.REMOVE๋Š” ๋ถ€๋ชจ Entity๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ์ž์‹ Entity๋„ ์‚ญ์ œ๋œ๋‹ค.
์ฆ‰, ๋ถ€๋ชจ๊ฐ€ ์ž์‹์˜ ์‚ญ์ œ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
์—ฌ๊ธฐ์„œ CascadeType.REFRESH๋„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ๋ถ€๋ชจ๊ฐ€ ์ž์‹์˜ ์ „์ฒด ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.
ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด๋„ ๋ถ€๋ชจ Entity๊ฐ€ ์ž์‹ Entity์™€์˜ ๊ด€๊ฒŒ๋ฅผ ์ œ๊ฑฐํ•ด๋„ ์ž์‹ Entity๋Š” ์‚ญ์ œ๋˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋‹ค.

orphanRemoval=true ๋˜ํ•œ ๋ถ€๋ชจ Entity๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ์ž์‹ Entity๋„ ์‚ญ์ œ๋œ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ CascadeType.REMOVE์™€๋Š” ๋‹ฌ๋ฆฌ, ๋ถ€๋ชจ Entity๊ฐ€ ์ž์‹ Entity์™€์˜ ๊ด€๊ณ„๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด ์ž์‹์€ ๊ณ ์•„๋กœ ์ทจ๊ธ‰๋˜์–ด ๊ทธ๋Œ€๋กœ ์‚ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค.

์ด ๋‘˜์€ ๋ถ€๋ชจ Entity๋ฅผ ์‚ญ์ œํ•  ๋•Œ๋Š” ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ๋ถ€๋ชจ Entity์—์„œ ์ž์‹ Entity์™€์˜ ๊ด€๊ณ„๋ฅผ ์ œ๊ฑฐํ•  ๋•Œ ์ฐจ์ด์ ์„ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.


์ฃผ์˜์ 

๋‘ ์˜ต์…˜ ๋ชจ๋‘ ์ž์‹ Entity์— ๋”ฑ ํ•˜๋‚˜์˜ ๋ถ€๋ชจ Entity๊ฐ€ ์—ฐ๊ด€๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค!
Member(์ž์‹)์„ Team(๋ถ€๋ชจ)๋„ ์•Œ๊ณ  Parent(๋ถ€๋ชจ)๋„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด, CascadeType.REMOVE ๋˜๋Š” orphanRemoval=true์˜ ์‚ฌ์šฉ์„ ์กฐ์‹ฌํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ์ž์‹ Entity๋ฅผ ์‚ญ์ œํ•  ์ƒํ™ฉ์ด ์•„๋‹Œ๋ฐ๋„ ์–ด๋Š ํ•œ ์ชฝ์˜ ๋ถ€๋ชจ Entity๋ฅผ ์‚ญ์ œํ–ˆ๊ฑฐ๋‚˜ ๋ถ€๋ชจ Entity๋กœ๋ถ€ํ„ฐ ์ œ๊ฑฐ๋๋‹ค๊ณ  ์ž์‹์ด ์‚ญ์ œ๋˜๋Š” ๋ถˆ์ƒ์‚ฌ๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ @OneToMany์—์„œ ํ™œ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ , @ManyToMany์—์„œ๋Š” ํ™œ์šฉ์„ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.


References

https://zzang9ha.tistory.com/350

 

JPA ์—ฐ๊ด€๊ด€๊ณ„ ์˜์†์„ฑ ์ „์ด(CASCADE) - CascadeType

๐Ÿ“Ž JPA ์˜์†์„ฑ ์ „์ด(CASCADE) ์•ˆ๋…•ํ•˜์„ธ์š”! ์ด๋ฒˆ์— ์ •๋ฆฌํ•  ๋‚ด์šฉ์€ JPA์—์„œ ์˜์†์„ฑ ์ „์ด(CASCADE)์™€ ๊ด€๋ จ๋œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ์ตœ๊ทผ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋ฉฐ ๋‘ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ์—์„œ save()๋ฅผ ํ•˜๋Š” ๊ณผ์ •์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ

zzang9ha.tistory.com

https://data-make.tistory.com/668

 

[JPA] Spring JPA CascadeType ์ข…๋ฅ˜

JPA Cascade Types Spring JPA CascadeType ์ข…๋ฅ˜ javax.persistence.CascadeType JPA Cascade Type ALL PERSIST MERGE REMOVE REFRESH DETACH CascadeType.ALL ์ƒ์œ„ ์—”ํ„ฐํ‹ฐ์—์„œ ํ•˜์œ„ ์—”ํ„ฐํ‹ฐ๋กœ ๋ชจ๋“  ์ž‘์—…์„ ์ „ํŒŒ @Entity public class Person { @Id @Gen

data-make.tistory.com

https://velog.io/@rara_kim/JPA-CascadeType-์ข…๋ฅ˜

 

[JPA] CascadeType ์ข…๋ฅ˜

๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†ํ™”๋  ๋•Œ ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋„ ๊ฐ™์ด ์˜์†ํ™”๋˜๊ณ , ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์‚ญ์ œ๋  ๋•Œ ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋„ ์‚ญ์ œ๋˜๋Š” ๋“ฑ ํŠน์ • ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์† ์ƒํƒœ๋กœ ๋งŒ๋“ค ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์˜์† ์ƒํƒœ๋กœ ์ „์ด๋˜

velog.io