일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- AI
- 티스토리챌린지
- Java
- minikube
- kotlin spring
- CloudWatch
- kotlin querydsl
- 코틀린 코루틴의 정석
- kotlin
- 오블완
- IntelliJ
- Elasticsearch
- CKA
- 정보처리기사 실기 기출문제
- APM
- mysql 튜닝
- Spring
- Kubernetes
- CKA 기출문제
- aws
- PETERICA
- kotlin coroutine
- 정보처리기사 실기
- Linux
- AWS EKS
- 공부
- MySQL
- 정보처리기사실기 기출문제
- 기록으로 실력을 쌓자
- Pinpoint
- Today
- Total
피터의 개발이야기
[JPA] CascadeType.REMOVE과 orphanRemoval=true, MySQL DELETE CASCADE 비교 본문
[JPA] CascadeType.REMOVE과 orphanRemoval=true, MySQL DELETE CASCADE 비교
기록하는 백앤드개발자 2024. 8. 2. 10:10
ㅁ 들어가며
ㅇ JPA를 사용하면서 CascadeType.REMOVE와 orphanRemoval=true 옵션의 차이를 제대로 이해하지 못하였다.
ㅇ 두 옵션 모두 엔티티 간의 관계를 관리하는 데 사용되지만, 그 목적과 동작 방식에는 차이가 있다.
ㅇ 이 글에서는 두 옵션의 차이를 설명하고, 언제 어떤 옵션을 사용해야 하는지 알아보았다.
ㅇ [JPA] CascadeType.REMOVE vs orphanRemoval=true 차이점 알아보기을 참조하여 작성하였다.
ㅁ CascadeType.REMOVE
ㅇ 부모 엔티티가 삭제될 때, 연관된 자식 엔티티도 함께 삭제되도록 설정하는 옵션이다.
@Entity
class Parent(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@OneToMany(mappedBy = "parent", cascade = [CascadeType.REMOVE])
val children: MutableList<Child> = mutableListOf()
)
@Entity
class Child(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@ManyToOne
@JoinColumn(name = "parent_id")
val parent: Parent
)
ㅇ 부모 엔티티가 삭제될 때 자식 엔티티도 함께 삭제되어야 하는 경우.
ㅇ 예를 들면, 게시글을 삭제할 때 해당 게시글에 달린 댓글도 함께 삭제되어야 한다.
ㅇ Parent와 Child의 관계가 끊어진 Child는 삭제 하지 않는다.
ㅁ orphanRemoval=true
@Entity
class Parent(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@OneToMany(mappedBy = "parent", orphanRemoval = true)
val children: MutableList<Child> = mutableListOf()
)
@Entity
class Child(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,
@ManyToOne
@JoinColumn(name = "parent_id")
val parent: Parent
)
ㅇ 부모 엔티티와의 관계가 끊어진 자식 엔티티(고아 객체)를 자동으로 삭제하는 옵션이다.
ㅇ 예를 들어, 쇼핑 카트에서 상품을 제거할 때 해당 상품이 더 이상 다른 카트에 속하지 않는다면 삭제해야 한다.
ㅁ 차이점 정리
CascadeType.REMOVE:부모 엔티티가 삭제될 때, 연관된 자식 엔티티도 함께 삭제될 때 사용하지만,
orphanRemoval=true: 부모 엔티티와의 관계가 끊어진 자식 엔티티(고아 객체)를 자동으로 데이터베이스에서도 삭제된다.
두 옵션 모두 부모가 삭제되면 자식 엔티티를 삭제하지만,
CascadeType.REMOVE은 부모의 입장에서 자식을 삭제하고,
orphanRemoval=true은 자식의 입장에서 부모와 관계가 없는 고아 객체 시 삭제된다.
JPA, CascadeType.REMOVE와 MySQL의 DELETE CASCADE도 기능상 유사하지만 차이점이 있다.
ㅁ MySQL의 DELETE CASCADE
ㅇ MySQL에서 DELETE CASCADE는 부모 테이블의 레코드가 삭제될 때 연관된 자식 테이블의 레코드도 자동으로 삭제한다.
ㅇ 데이터베이스 계층에서 데이터베이스가 직접 삭제한다.
CREATE TABLE 부서
(
부서코드 INT PRIMARY KEY,
부서명 VARCHAR(20)
);
INSERT INTO 부서 VALUES (10, '영업부');
INSERT INTO 부서 VALUES (20, '기획부');
INSERT INTO 부서 VALUES (30, '개발부');
CREATE TABLE 직원
(
직원코드 INT PRIMARY KEY,
부서코드 INT,
직원명 VARCHAR(20),
FOREIGN KEY (부서코드) REFERENCES 부서 (부서코드)
ON DELETE CASCADE
);
INSERT INTO 직원 VALUES (1001, 10, '이진수');
INSERT INTO 직원 VALUES (1002, 10, '곽연경');
INSERT INTO 직원 VALUES (1003, 20, '김선길');
INSERT INTO 직원 VALUES (1004, 20, '최민수');
INSERT INTO 직원 VALUES (1005, 20, '이용갑');
INSERT INTO 직원 VALUES (1006, 30, '박종일');
INSERT INTO 직원 VALUES (1007, 30, '박미경');
ㅇ 부서와 직원 테이블과 데이터를 생성하였다.
# 부서 삭제 전 직원 현황
SELECT 부서코드, count(*) cnt
from 직원
group by 부서코드;
# 10,2
# 20,3
# 30,2
# 부서 삭제
delete from 부서 where 부서코드 = 10;
# 부서에 속한 직원 삭제 확인
SELECT 부서코드, count(*) cnt
from 직원
group by 부서코드;
# 20,3
# 30,2
ㅇ 부서를 삭제하면 관련된 직원도 함께 삭제되었다.
ㅁ 차이점 정리
ㅇ CascadeType.REMOVE와 MySQL의 DELETE CASCADE는 모두 관련 데이터를 삭제하는 기능은 같다.
ㅇ 하지만, 작동 방식과 적용 계층이 다르다.
CascadeType.REMOVE | MySQL - DELETE CASCADE | |
적용범위 | JPA 엔티티 간의 관계 | 데이터베이스 테이블 간의 관계 |
제어 | 애플리케이션에서 제어 가능 | 데이터베이스 수준에서 자동으로 동작 |
성능 | 각 엔티티에 대해 개별 DELETE 쿼리 실행 | 데이터베이스 엔진이 최적화된 방식으로 삭제 수행 |
유연성 | 비즈니스 로직에 따라 선택적으로 적용 가능 | 항상 적용되며, 예외 처리가 어려움 |
ㅇ 두 방식은 상황에 따라 적절히 선택하거나 함께 사용할 수 있다.
ㅇ 애플리케이션의 요구사항, 성능 고려사항, 데이터 일관성 등을 고려하여 적절한 방식을 선택해야 한다.
ㅁ 함께 보면 좋은 사이트
'Programming > Spring' 카테고리의 다른 글
[Spring] Kotlin으로 JPA Querydsl 세팅 (0) | 2024.08.09 |
---|---|
[Spring] Gradle 9.0 호환성 경고 해결하기, Deprecated Gradle features were used in this build (0) | 2024.08.08 |
[JPA] GenerationType(AUTO, IDENTITY, SEQUENCE ,TABLE) 기본 키 생성 전략 (0) | 2024.07.06 |
[QueryDSL] querydsl관련 명령어를 gradle탭에 생성하기, querydsl plugin 설치 (0) | 2024.07.05 |
[Spring] Gradle 프로젝트에서 테스트를 스킵하는 방법 (0) | 2024.07.03 |