관리 메뉴

피터의 개발이야기

[JPA] CascadeType.REMOVE과 orphanRemoval=true, MySQL DELETE CASCADE 비교 본문

Programming/Spring

[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 쿼리 실행 데이터베이스 엔진이 최적화된 방식으로 삭제 수행
유연성 비즈니스 로직에 따라 선택적으로 적용 가능 항상 적용되며, 예외 처리가 어려움

ㅇ 두 방식은 상황에 따라 적절히 선택하거나 함께 사용할 수 있다.

ㅇ 애플리케이션의 요구사항, 성능 고려사항, 데이터 일관성 등을 고려하여 적절한 방식을 선택해야 한다.

 

ㅁ 함께 보면 좋은 사이트

Cascade 이해 및 orphanRemoval=true vs CascadeType.REMOVE

[JPA] CascadeType.REMOVE vs orphanRemoval=true 차이점 알아보기

반응형
Comments