일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- set
- SEO
- @Controller
- @Entity
- GA4
- useEffect
- JPA
- 구글애널리틱스
- 워드프레스
- post
- @Query
- mergeattributes()
- 플러그인
- GET
- 데이터베이스
- @Repository
- HttpSession
- ChatGPT
- addallattributes()
- Thymeleaf
- 리액트오류
- Polylang
- router
- Login
- db
- linkedhastset
- 구글알고리즘
- 구글
- firebase
- 인텔리제이
- Today
- Total
개발천재
[Spring Boot] JPA Cascade 완벽 가이드 본문
JPA의 Cascade(영속성 전이) 이해하기
JPA에서 영속성 전이(Cascade) 란, 부모 엔티티가 저장되거나 삭제될 때 연관된 자식 엔티티도 함께 처리되도록 하는 기능이다. 예를 들어, 부모를 데이터베이스에 저장하면 자식도 자동으로 저장되거나, 부모를 삭제하면 자식도 같이 삭제되도록 설정할 수 있다.
이를 통해 연관된 객체를 일일이 관리하지 않아도 되므로 코드가 간결해지고 유지보수가 쉬워진다는 장점이 있지만 부모를 삭제할 때 자식까지 예상치 않게 삭제될 수도 있으므로 신중하게 사용해야 한다.
@Entity
class Parent {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
}
Cascade가 필요한 이유
관계형 데이터베이스에서 부모-자식 관계(예: @OneToMany, @ManyToOne)를 맺을 때, 부모 엔티티가 변경되면 자식 엔티티도 함께 변경되도록 만들기 위해 사용된다.
예를 들어, 부모 엔티티를 저장할 때 자식 엔티티도 자동으로 저장되도록 하려면 CascadeType.PERSIST를 설정하면 된다.
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
CascadeType 종류
ALL
모든 영속성 전이 (PERSIST, MERGE, REMOVE, REFRESH, DETACH 전부 적용)
cascade = CascadeType.ALL
PERSIST
부모 엔티티를 저장할 때 자식 엔티티도 함께 저장
cascade = CascadeType.PERSIST
MERGE
부모 엔티티를 병합할 때 자식 엔티티도 함께 병합
cascade = CascadeType.MERGE
REMOVE
부모 엔티티를 삭제하면 자식 엔티티도 함께 삭제
cascade = CascadeType.ALL
REFRESH
부모 엔티티를 다시 조회하면 자식 엔티티도 함께 새로고침
cascade = CascadeType.REMOVE
DETACH
부모 엔티티를 영속성 컨텍스트에서 분리할 때 자식 엔티티도 함께 분리
cascade = CascadeType.DETACH
Cascade 적용 예제
CascadeType.PERSIST
부모 엔티티를 저장할 때, 연관된 자식 엔티티도 함께 저장된다.
@Entity
class Parent {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
}
@Entity
class Child {
@Id @GeneratedValue
private Long id;
@ManyToOne
private Parent parent;
public void setParent(Parent parent) {
this.parent = parent;
}
}
Parent parent = new Parent();
Child child1 = new Child();
Child child2 = new Child();
parent.addChild(child1);
parent.addChild(child2);
entityManager.persist(parent); // parent를 저장하면 child1, child2도 자동 저장됨
CascadeType.REMOVE
부모 엔티티가 삭제될 때, 연관된 자식 엔티티도 자동으로 삭제된다.
부모 삭제 시 자식도 모두 삭제되므로, 실제 데이터가 모두 사라지는 문제가 발생할 수 있다.
orphanRemoval = true와 함께 사용하면 부모가 자식 리스트에서 제거할 때 자동으로 삭제된다.
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
private List<Child> children = new ArrayList<>();
entityManager.remove(parent);
// parent를 삭제하면 children 리스트의 모든 child도 삭제됨
아이돌 그룹 멤버와 엔터테이먼트 엔티티로 보는 예시
// Entertainment Entity
@Entity
@Data
public class Entertainment {
@Id
@Column(name = "e_id")
private String id;
private String name;
@OneToMany(mappedBy = "entertainment",
fetch = FetchType.EAGER,
cascade = CascadeType.PERSIST)
List<GirlGroup> girlGroupList = new ArrayList<>();
}
// GirlGroup Entity
@Entity
@Data
public class GirlGroup {
@Id
@Column(name = "g_id")
private String id;
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "e_id")
Entertainment entertainment;
@OneToMany(mappedBy = "girlGroup",
fetch = FetchType.EAGER,
cascade = CascadeType.PERSIST)
List<IdolMember> idolMemberList = new ArrayList<>();
}
// IdolMember Entity
@Entity
@Data
public class IdolMember {
@Id
@Column(name = "i_id")
private String id;
private String name;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "g_id")
private GirlGroup girlGroup;
}
Service
@Service
@Transactional
public class ExamService {
@Autowired
EntityManager em;
public void initData() {
IdolMember member_1 = new IdolMember();
IdolMember member_2 = new IdolMember();
IdolMember member_3 = new IdolMember();
IdolMember member_4 = new IdolMember();
member_1.setId("안유진");
member_1.setName("유진");
member_2.setId("장원영");
member_2.setName("원영");
member_3.setId("제니");
member_3.setName("재니");
member_4.setId("지수");
member_4.setName("지수다");
GirlGroup girlGroup_1 = new GirlGroup();
GirlGroup girlGroup_2 = new GirlGroup();
girlGroup_1.setId("ive");
girlGroup_1.setName("아이브");
girlGroup_2.setId("blackPink");
girlGroup_2.setName("블핑");
Entertainment entertainment_1 = new Entertainment();
Entertainment entertainment_2 = new Entertainment();
entertainment_1.setId("startship");
entertainment_1.setName("스타쉽");
entertainment_2.setId("YG");
entertainment_2.setName("와이지");
// 🔥 관계 설정 (FK 설정)
member_1.setGirlGroup(girlGroup_1); // 유진 → 아이브
member_2.setGirlGroup(girlGroup_1); // 원영 → 아이브
member_3.setGirlGroup(girlGroup_2); // 재니 → 블핑
member_4.setGirlGroup(girlGroup_2); // 지수 → 블핑
girlGroup_1.setEntertainment(entertainment_1); // 아이브 → 스타쉽
girlGroup_2.setEntertainment(entertainment_2); // 블핑 → YG
// 🔥 @OneToMany 리스트에 추가
girlGroup_1.getIdolMemberList().add(member_1);
girlGroup_1.getIdolMemberList().add(member_2);
girlGroup_2.getIdolMemberList().add(member_3);
girlGroup_2.getIdolMemberList().add(member_4);
entertainment_1.getGirlGroupList().add(girlGroup_1);
entertainment_2.getGirlGroupList().add(girlGroup_2);
// 🔥 저장
em.persist(entertainment_1);
em.persist(entertainment_2);
em.persist(girlGroup_1);
em.persist(girlGroup_2);
em.persist(member_1);
em.persist(member_2);
em.persist(member_3);
em.persist(member_4);
}
}
'개발 준비 > Spring Boot' 카테고리의 다른 글
[Spring Boot] ResponseEntity, 유연한 HTTP 응답 처리하기 (2) | 2025.03.04 |
---|---|
[Spring Boot] @RestController, 효과적인 API 개발을 위한 핵심 가이드 (2) | 2025.03.04 |
[Spring Boot] JPQL로 이해하는 데이터베이스 접근 방식 (0) | 2025.02.27 |
[Spring Boot] JPA 매핑 어노테이션 정리 (1) | 2025.02.27 |
[Spring Boot] JPA 영속성 컨텍스트 완벽 이해: 개념부터 실전 활용까지 (1) | 2025.02.26 |